package com.xbongbong.pro.statistic.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.FieldAttrConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.constant.TimeConstant;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.domain.entity.PaasFormSubDataEntity;
import com.xbongbong.paas.domain.entity.ext.ConditionsEntityExt;
import com.xbongbong.paas.elasticsearch.pojo.ChartFieldsAnalysisEntityExt;
import com.xbongbong.paas.elasticsearch.pojo.StatisticBiFormDataEntity;
import com.xbongbong.paas.elasticsearch.pojo.XbbAggregatedPage;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.AggTypeEnum;
import com.xbongbong.paas.enums.BIProductReformEnum;
import com.xbongbong.paas.enums.BISubProductCommonFieldEnum;
import com.xbongbong.paas.enums.ConditionEnum;
import com.xbongbong.paas.enums.DateDiffTypeEnum;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.EsAliasEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.enums.UnitEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.field.SubFormPoJo;
import com.xbongbong.paas.help.CommonHelp;
import com.xbongbong.sys.help.PackageHelp;
import com.xbongbong.paas.model.PaasFormExplainModel;
import com.xbongbong.paas.pojo.IdNamePojo;
import com.xbongbong.paas.redis.PaasRedisHelper;
import com.xbongbong.paas.redis.RedisConstant;
import com.xbongbong.paas.redis.RedisPrefixConstant;
import com.xbongbong.paas.redis.RedisTimeConstant;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.helper.PageHelper;
import com.xbongbong.paas.toolbox.helper.ReflectHelper;
import com.xbongbong.paas.toolbox.thread.ThreadLocalUtil;
import com.xbongbong.paas.toolbox.thread.TransmittableThreadLocalUtil;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CalendarUtil;
import com.xbongbong.paas.toolbox.util.CloneUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.JsonHelperUtil;
import com.xbongbong.paas.toolbox.util.PageHelperUtil;
import com.xbongbong.paas.toolbox.util.RegexUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.BaseDTO;
import com.xbongbong.paas.toolbox.wrap.UserVO;
import com.xbongbong.paas.toolbox.wrap.XbbResponse;
import com.xbongbong.pro.constant.BusinessConstant;
import com.xbongbong.pro.constant.CommonConstant;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.constant.SymbolConstant;
import com.xbongbong.pro.domain.entity.ChartCategoryEntity;
import com.xbongbong.pro.domain.entity.ChartEntity;
import com.xbongbong.pro.enums.AccessLinkEnum;
import com.xbongbong.pro.enums.DistributorMarkEnum;
import com.xbongbong.pro.enums.ReportTypeEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.TimeTypeEnum;
import com.xbongbong.pro.enums.errorcodes.BiErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.ChartErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.PerformanceErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.StatisticsServicesErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.global.ChartCategoryEnum;
import com.xbongbong.pro.performanceset.pojo.PerformanceSetExplainPojo;
import com.xbongbong.pro.service.toolbox.statistic.help.ChartDtoHelp;
import com.xbongbong.pro.service.toolbox.statistic.help.ChartPkRuleHelp;
import com.xbongbong.pro.service.toolbox.statistic.help.ChartQueryHelp;
import com.xbongbong.pro.service.toolbox.statistic.help.ChartRuleQueryHelp;
import com.xbongbong.pro.service.toolbox.statistic.help.FiscalYearHelp;
import com.xbongbong.pro.service.toolbox.statistic.help.PerformanceHelp;
import com.xbongbong.pro.service.toolbox.statistic.help.PkRuleHelp;
import com.xbongbong.pro.service.toolbox.statistic.help.SystemChartHelp;
import com.xbongbong.pro.service.toolbox.statistic.help.ThroughHelp;
import com.xbongbong.pro.service.toolbox.statistic.util.ChartResultUtil;
import com.xbongbong.pro.service.toolbox.statistic.util.PerformanceUtil;
import com.xbongbong.pro.statistic.abstracts.AbstractChartResultBase;
import com.xbongbong.pro.statistic.constant.ChartCommonConstant;
import com.xbongbong.pro.statistic.constant.ChartConstant;
import com.xbongbong.pro.statistic.constant.EsFieldConstant;
import com.xbongbong.pro.statistic.constant.FundStatisticsConstant;
import com.xbongbong.pro.statistic.enums.AdvancedComputingFirstEnum;
import com.xbongbong.pro.statistic.enums.AdvancedComputingSecondEnum;
import com.xbongbong.pro.statistic.enums.ChartAggNameEnum;
import com.xbongbong.pro.statistic.enums.ChartAggResultEnum;
import com.xbongbong.pro.statistic.enums.ChartTypeEnum;
import com.xbongbong.pro.statistic.enums.FundFlowEnum;
import com.xbongbong.pro.statistic.enums.NumFormatEnum;
import com.xbongbong.pro.statistic.enums.RateTypeEnum;
import com.xbongbong.pro.statistic.enums.ResultFromEnum;
import com.xbongbong.pro.statistic.enums.ReturnTypeEnum;
import com.xbongbong.pro.statistic.enums.StatisticsTypeEnum;
import com.xbongbong.pro.statistic.enums.SystemCodeAnnotateEnum;
import com.xbongbong.pro.statistic.enums.SystemCodeEnum;
import com.xbongbong.pro.statistic.enums.TimeDimensionEnum;
import com.xbongbong.pro.statistic.enums.ValueTypeEnum;
import com.xbongbong.pro.statistic.factory.ChartAnalysisFactory;
import com.xbongbong.pro.statistic.factory.ChartStrategyFactory;
import com.xbongbong.pro.statistic.help.BiSubFormDataMultiHandle;
import com.xbongbong.pro.statistic.help.BiSubFormDataSingleHandle;
import com.xbongbong.pro.statistic.help.ChartAttrHelp;
import com.xbongbong.pro.statistic.help.ChartResultHelp;
import com.xbongbong.pro.statistic.help.CustomHelp;
import com.xbongbong.pro.statistic.manager.feign.DiyResultFeignClient;
import com.xbongbong.pro.statistic.model.ChartCategoryModel;
import com.xbongbong.pro.statistic.model.ChartCustomModel;
import com.xbongbong.pro.statistic.model.ChartModel;
import com.xbongbong.pro.statistic.pojo.BiaxialInfoPojo;
import com.xbongbong.pro.statistic.pojo.ChartFieldAttrPojo;
import com.xbongbong.pro.statistic.pojo.ChartParamPojo;
import com.xbongbong.pro.statistic.pojo.DwTriggerConditionPojo;
import com.xbongbong.pro.statistic.pojo.ExplainsPojo;
import com.xbongbong.pro.statistic.pojo.FiscalYearTimePojo;
import com.xbongbong.pro.statistic.pojo.SlaveSourcePojo;
import com.xbongbong.pro.statistic.pojo.TimePojo;
import com.xbongbong.pro.statistic.pojo.dto.ChartSubFormListDTO;
import com.xbongbong.pro.statistic.pojo.dto.SocketResultDTO;
import com.xbongbong.pro.statistic.pojo.vo.ChartSubFormListVO;
import com.xbongbong.pro.statistic.pojo.vo.DataWarningQueryListVO;
import com.xbongbong.pro.statistic.pojo.vo.DataWarningQueryVO;
import com.xbongbong.pro.statistic.pojo.vo.SocketReckonVO;
import com.xbongbong.pro.statistic.result.pojo.AggsBucketsPojo;
import com.xbongbong.pro.statistic.result.pojo.CallLogAggsPojo;
import com.xbongbong.pro.statistic.result.pojo.ChartIdPojo;
import com.xbongbong.pro.statistic.result.pojo.ChartResultPkPojo;
import com.xbongbong.pro.statistic.result.pojo.ChartResultPojo;
import com.xbongbong.pro.statistic.result.pojo.ChartResultRedisPojo;
import com.xbongbong.pro.statistic.result.pojo.ChartRlWarningDataPojo;
import com.xbongbong.pro.statistic.result.pojo.ChartRlWarningPojo;
import com.xbongbong.pro.statistic.result.pojo.ChartStatisticsPojo;
import com.xbongbong.pro.statistic.result.pojo.ElasticAggsPojo;
import com.xbongbong.pro.statistic.result.pojo.FieldAttrPojo;
import com.xbongbong.pro.statistic.result.pojo.FundFlowInfoPojo;
import com.xbongbong.pro.statistic.result.pojo.PkInfoPojo;
import com.xbongbong.pro.statistic.result.pojo.PkPerforInfoPojo;
import com.xbongbong.pro.statistic.result.pojo.SalesReportPojo;
import com.xbongbong.pro.statistic.result.pojo.TitlePojo;
import com.xbongbong.pro.statistic.result.pojo.TitleRightPojo;
import com.xbongbong.pro.statistic.result.pojo.WarningValuePojo;
import com.xbongbong.pro.statistic.result.pojo.dto.ChartResultAggDTO;
import com.xbongbong.pro.statistic.result.pojo.dto.ChartResultBaseDTO;
import com.xbongbong.pro.statistic.result.pojo.dto.ChartResultCallStatisticsDTO;
import com.xbongbong.pro.statistic.result.pojo.dto.ChartResultDTO;
import com.xbongbong.pro.statistic.result.pojo.dto.ChartResultPerformancePkDTO;
import com.xbongbong.pro.statistic.result.pojo.dto.DiyResultDTO;
import com.xbongbong.pro.statistic.result.pojo.vo.CallStatisticsVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ChartResultAggVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ChartResultDetailVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ChartResultPkDetailVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ChartResultPkVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ChartResultVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ChartResultValueDetailVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ChartResultValueVO;
import com.xbongbong.pro.statistic.result.pojo.vo.FundFlowDetailVO;
import com.xbongbong.pro.statistic.result.pojo.vo.FundFlowVO;
import com.xbongbong.pro.statistic.result.pojo.vo.IndexVO;
import com.xbongbong.pro.statistic.result.pojo.vo.PerformanceFinishVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ResultChartVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ResultDataChartVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ResultDataSeriesChartVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ResultDataTableVO;
import com.xbongbong.pro.statistic.result.pojo.vo.ResultTableVO;
import com.xbongbong.pro.statistic.result.pojo.vo.SalesReportVO;
import com.xbongbong.pro.statistic.service.ChartCustomService;
import com.xbongbong.pro.statistic.service.ChartLimitService;
import com.xbongbong.pro.statistic.service.ChartResultProService;
import com.xbongbong.pro.statistic.service.ChartResultService;
import com.xbongbong.pro.statistic.service.result.ChartResult;
import com.xbongbong.pro.statistic.service.result.CrmCallLogResult;
import com.xbongbong.pro.statistic.service.result.FundResult;
import com.xbongbong.pro.statistic.through.pojo.dto.ThroughDTO;
import com.xbongbong.pro.statistic.util.ChartUtil;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.CustomChartConstant;
import com.xbongbong.saas.constant.ErrorMessageConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.BiUserTeamEntity;
import com.xbongbong.saas.domain.entity.FundAccountEntity;
import com.xbongbong.saas.domain.entity.PerformanceEntity;
import com.xbongbong.saas.domain.entity.ProductCategoryEntity;
import com.xbongbong.saas.domain.entity.ext.CustomerEntityExt;
import com.xbongbong.saas.domain.entity.ext.ProductEntityExt;
import com.xbongbong.saas.enums.AssessTypeEnum;
import com.xbongbong.saas.enums.BirthdayTypeEnum;
import com.xbongbong.saas.enums.CallCenterCallLogCallSourceEnum;
import com.xbongbong.saas.enums.CallLogTypeEnum;
import com.xbongbong.saas.enums.CompanyConfigEnum;
import com.xbongbong.saas.enums.ReportTargetEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ClueEnum;
import com.xbongbong.saas.enums.business.ContractPerformanceEnum;
import com.xbongbong.saas.enums.business.CustomerManagementEnum;
import com.xbongbong.saas.enums.business.DistributorAccountEnum;
import com.xbongbong.saas.enums.business.DistributorEnum;
import com.xbongbong.saas.enums.business.ProductEnum;
import com.xbongbong.saas.help.FundHelp;
import com.xbongbong.saas.model.CustomerModel;
import com.xbongbong.saas.model.FundAccountModel;
import com.xbongbong.saas.model.IndexTypeModel;
import com.xbongbong.saas.model.PerformanceModel;
import com.xbongbong.saas.model.ProductCategoryModel;
import com.xbongbong.saas.model.ProductModel;
import com.xbongbong.saas.model.WorkOrderExplainModel;
import com.xbongbong.saas.service.toolbox.help.AttrDecimalPrecisionHelper;
import com.xbongbong.saas.service.toolbox.help.SaasListDataPermissionHelp;
import com.xbongbong.saas.toolbox.help.BasicHelper;
import com.xbongbong.saas.toolbox.help.SortHelp;
import com.xbongbong.sys.domain.entity.CompanyConfigEntity;
import com.xbongbong.sys.domain.entity.DepartmentEntity;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.sys.enums.CompanyStructTypeEnum;
import com.xbongbong.sys.enums.DataPermissionEnum;
import com.xbongbong.sys.model.CompanyConfigModel;
import com.xbongbong.sys.model.DepartmentModel;
import com.xbongbong.sys.model.UserModel;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.join.aggregations.ChildrenAggregationBuilder;
import org.elasticsearch.join.aggregations.JoinAggregationBuilders;
import org.elasticsearch.join.aggregations.ParsedChildren;
import org.elasticsearch.script.Script;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation;
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
import org.elasticsearch.search.aggregations.bucket.histogram.ParsedDateHistogram;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.Avg;
import org.elasticsearch.search.aggregations.metrics.AvgAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.Max;
import org.elasticsearch.search.aggregations.metrics.MaxAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.Min;
import org.elasticsearch.search.aggregations.metrics.MinAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.ParsedAvg;
import org.elasticsearch.search.aggregations.metrics.ParsedMax;
import org.elasticsearch.search.aggregations.metrics.ParsedMin;
import org.elasticsearch.search.aggregations.metrics.ParsedSum;
import org.elasticsearch.search.aggregations.metrics.ParsedValueCount;
import org.elasticsearch.search.aggregations.metrics.Sum;
import org.elasticsearch.search.aggregations.metrics.SumAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.ValueCount;
import org.elasticsearch.search.aggregations.metrics.ValueCountAggregationBuilder;
import org.elasticsearch.search.aggregations.pipeline.ParsedSimpleValue;
import org.elasticsearch.search.aggregations.pipeline.SimpleValue;
import org.elasticsearch.search.aggregations.support.ValuesSourceAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static com.xbongbong.paas.enums.IndexTypeEnum.IDX_SAAS_CUSTOMER_COMMUNICATE;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.existsQuery;
import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * 图表/指标统计结果相关
 * @author zcp
 * @version v1.0
 * @date 2019/3/27 15:51
 * @since v1.0
 */
@Service("chartResultService")
public class ChartResultServiceImpl extends AbstractChartResultBase implements ChartResultService {
    private static final Logger LOG = LoggerFactory.getLogger(ChartResultServiceImpl.class);
    @Resource
    private ChartModel chartModel;
    @Resource
    private ChartCustomModel chartCustomModel;
    @Resource
    private ChartCategoryModel chartCategoryModel;
    @Resource
    private DepartmentModel departmentModel;
    @Resource
    private UserModel userModel;
    @Resource
    private CompanyConfigModel companyConfigModel;
    @Resource
    private PerformanceModel performanceModel;
    @Resource
    private PerformanceHelp performanceHelp;
    @Resource
    private ChartDtoHelp chartDtoHelp;
    @Resource
    private CustomHelp customHelp;
    @Resource
    private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;
    @Resource
    private CommonHelp commonHelp;
    @Resource
    private ThroughHelp throughHelp;
    @Resource
    private ChartResult chartResult;
    @Resource
    private CrmCallLogResult crmCallLogResult;
    @Resource
    private SystemChartHelp systemChartHelp;
    @Resource
    private EsHelper esHelper;
    @Resource
    private AttrDecimalPrecisionHelper attrDecimalPrecisionHelper;
    @Resource
    private PaasRedisHelper paasRedisHelper;
    @Resource
    private ChartQueryHelp chartQueryHelp;
    @Resource
    private FundAccountModel fundAccountModel;
    @Resource
    private FundHelp fundHelp;
    @Resource
    private FundResult fundResult;
    @Resource
    private PaasFormExplainModel paasFormExplainModel;
    @Resource
    private SaasListDataPermissionHelp saasListDataPermissionHelp;
    @Resource
    private ProductCategoryModel productCategoryModel;
    @Resource
    private WorkOrderExplainModel workOrderExplainModel;
    @Resource
    private BiSubFormDataSingleHandle biSubFormDataSingleHandle;
    @Resource
    private BiSubFormDataMultiHandle biSubFormDataMultiHandle;
    @Resource
    private CustomerModel customerModel;
    @Resource
    private PkRuleHelp pkRuleHelp;
    @Resource
    private ChartRuleQueryHelp chartRuleQueryHelp;
    @Resource
    private ChartCustomService chartCustomService;
    @Resource
    private DiyResultFeignClient diyResultFeignClient;
    @Resource
    private ChartResultHelp chartResultHelp;
    @Resource
    private ChartLimitService chartLimitService;
    @Resource
    private ProductModel productModel;
    @Resource
    private IndexTypeModel indexTypeModel;
    @Resource
    private PackageHelp packageHelp;
    @Resource
    private ChartPkRuleHelp chartPkRuleHelp;
    @Resource
    private ChartAttrHelp chartAttrHelp;
    @Resource
    private ChartStrategyFactory chartStrategyFactory;

    @Override
    public void filterByDriverSource(ChartResultDTO chartResultDTO, ChartParamPojo chartParamPojo, ChartEntity chartEntity) throws XbbException {
        return;
    }

    @Override
    public ChartResultDetailVO getDiyResult(ChartEntity chartEntity, ChartResultPojo chartResultPojo, List<PaasFormExplainEntity> explainEntityList, List<JSONObject> search,boolean penetrateFlag) throws XbbException {
        return getResult(chartEntity,chartResultPojo,explainEntityList,search,penetrateFlag);
    }

    @Override
    public ChartResultVO chartResult(ChartResultDTO chartResultDTO) throws XbbException {
        return getChartResult(chartResultDTO);
    }

    /**
     * @Description 图表数据显示时，根据字段去数据库查询
     * @author weiming
     * @Date  2020/5/22 9:43
     * @since
     **/
    @Override
    public JSONArray updateExplain(JSONArray attrJsonArray, List<PaasFormExplainEntity> explainEntityList, Integer single, String corpid) throws XbbException {
        JSONArray jsonArray = new JSONArray();
        if (explainEntityList != null && explainEntityList.size() > 0) {
            //将formId作为key，explain作为value
            Map<Long, String> explainMap = explainEntityList.stream().collect(Collectors.toMap(paasFormExplainEntity -> paasFormExplainEntity.getFormId(), paasFormExplainEntity -> paasFormExplainEntity.getExplains()));
            for (int i = 0; i < attrJsonArray.size(); i++) {
                JSONObject jsonObject = attrJsonArray.getJSONObject(i);
                long formId = jsonObject.getLong(StringConstant.FORM_ID);
                JSONArray explainJsonArray = JSONObject.parseArray(explainMap.get(formId));
                if (Objects.equals(FieldTypeEnum.COMPUTED_FIELD.getType(), jsonObject.getInteger(FieldAttrConstant.FIELD_TYPE))
                        || Objects.equals(FieldTypeEnum.COUNT.getType(), jsonObject.getInteger(FieldAttrConstant.FIELD_TYPE))
                        || Objects.equals(FieldTypeEnum.ADDRESS.getType(), jsonObject.getInteger(FieldAttrConstant.FIELD_TYPE))
                        || explainJsonArray == null
                ) {
                    JsonHelperUtil.addToJSONArray(jsonArray, jsonObject);
                    continue;
                }
                for (int j = 0; j < explainJsonArray.size(); j++) {
                    JSONObject explainJsonObject = explainJsonArray.getJSONObject(j);
                    String explainAttr = explainJsonObject.getString(StringConstant.ATTR);
                    String objectAttr = jsonObject.getString(FieldAttrConstant.ORIGINALATTR);
                    boolean flag = explainAttr.equals(jsonObject.getString(StringConstant.ATTR));
                    if (single == 0 && Objects.nonNull(objectAttr)){
                        flag = objectAttr.equals(explainAttr);
                    }
                    Integer objFieldType = jsonObject.getInteger(FieldAttrConstant.FIELD_TYPE);
                    Integer expFieldType = explainJsonObject.getInteger(FieldAttrConstant.FIELD_TYPE);
                    //根据attrName匹配explain，替换
                    if (((Objects.equals(FieldTypeEnum.SUB_FORM.getType(), objFieldType)
                            &&Objects.equals(FieldTypeEnum.SUB_FORM.getType(), expFieldType))||
                            (Objects.equals(FieldTypeEnum.CONTACT_NUMBER.getType(), objFieldType)
                                    &&Objects.equals(FieldTypeEnum.CONTACT_NUMBER.getType(), expFieldType))) && flag
                    ) {
                        jsonObject.put(StringConstant.ATTR_NAME,explainJsonObject.getString(StringConstant.ATTR_NAME));
                        jsonObject.put(StringConstant.ITEMS,explainJsonObject.getJSONArray(StringConstant.ITEMS));
                        JSONObject subFormJsonObject = explainJsonObject.getJSONObject(FieldAttrConstant.SUB_FORM);
                        JSONArray explainItems = subFormJsonObject.getJSONArray(StringConstant.ITEMS);
                        JSONArray jsonObjectItems = jsonObject.getJSONObject(FieldAttrConstant.SUB_FORM).getJSONArray(StringConstant.ITEMS);
                        JSONArray finalItems =new JSONArray();
                        for (int n = 0; n < jsonObjectItems.size(); n++) {
                            for (int m = 0; m < explainItems.size(); m++) {
                                JSONObject explainObject = explainItems.getJSONObject(m);
                                JSONObject displayObject = jsonObjectItems.getJSONObject(n);
                                if (displayObject.getString(StringConstant.ATTR).contains(EsAliasEnum.SUB_FORM.getEsAlias())) {
                                    if ((explainObject.getString(StringConstant.PARENT_ATTR)+StringConstant.POINT+explainObject.getString(StringConstant.ATTR)).equals(displayObject.getString(StringConstant.ATTR))) {
                                        displayObject.put(StringConstant.ATTR_NAME,explainObject.getString(StringConstant.ATTR_NAME));
                                        displayObject.put(StringConstant.ATTR,explainObject.getString(StringConstant.ATTR));
                                        displayObject.put(StringConstant.ITEMS,explainObject.getJSONArray(StringConstant.ITEMS));
                                        JsonHelperUtil.addToJSONArray(finalItems,displayObject);
                                        break;
                                    }
                                }else{
                                    if (explainObject.getString(StringConstant.ATTR).equals(displayObject.getString(StringConstant.ATTR))) {
                                        displayObject.put(StringConstant.ATTR_NAME,explainObject.getString(StringConstant.ATTR_NAME));
                                        displayObject.put(StringConstant.ITEMS,explainObject.getJSONArray(StringConstant.ITEMS));
                                        JsonHelperUtil.addToJSONArray(finalItems,displayObject);
                                        break;
                                    }
                                }
                            }
                        }
                        jsonObject.getJSONObject(FieldAttrConstant.SUB_FORM).put(StringConstant.ITEMS,finalItems);
                        JsonHelperUtil.addToJSONArray(jsonArray,jsonObject);
                        break;
                    }
                    if (single == 0) {
                        if (objectAttr == null) {
                            objectAttr = jsonObject.getString(StringConstant.ATTR);
                        }
                        if (explainAttr != null && explainAttr.equals(objectAttr)) {
                            Set<String> set = explainJsonObject.keySet();
                            for (String s : set) {
                                if (StringConstant.ATTR_NAME.equals(s)){
                                    jsonObject.put(s, explainJsonObject.get(s));
                                }
                                if (StringConstant.ITEMS.equals(s)){
                                    FieldAttrEntity fieldAttrEntity = explainJsonObject.toJavaObject(FieldAttrEntity.class);
                                    chartAttrHelp.getItems(fieldAttrEntity,jsonObject.getInteger("businessType"),corpid,jsonObject.getLong("formId"));
                                    jsonObject.put(s,fieldAttrEntity.getItems());
                                }
                            }
                            JsonHelperUtil.addToJSONArray(jsonArray, jsonObject);
                            break;
                        }
                    } else if (single == 1 && flag) {
                        Set<String> set = explainJsonObject.keySet();
                        for (String s : set) {
                            if (StringConstant.ATTR_NAME.equals(s) || Objects.equals("comboType", s)){
                                jsonObject.put(s, explainJsonObject.get(s));
                            } else if (StringConstant.ITEMS.equals(s)){
                                FieldAttrEntity fieldAttrEntity = explainJsonObject.toJavaObject(FieldAttrEntity.class);
                                chartAttrHelp.getItems(fieldAttrEntity, jsonObject.getInteger("businessType"), corpid, jsonObject.getLong("formId"));
                                jsonObject.put(s,fieldAttrEntity.getItems());
                            }
                        }
                        //如果是产品分类的话，需要去重新查找数据库的产品分类信息。
                        JSONArray selectedCategory = jsonObject.getJSONArray("selectedCategory");
                        if (selectedCategory != null) {
                            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                            param.put(StringConstant.CORPID, corpid);
                            param.put(StringConstant.DEL,0);
                            param.put("orderByStr", "sort ASC, update_time ASC ");
                            List<ProductCategoryEntity> allCay = productCategoryModel.findEntitys(param);
                            List<Long> categoryId = allCay.stream().map(ProductCategoryEntity::getId).collect(Collectors.toList());
                            for (int k = 0; k< selectedCategory.size(); k++) {
                                JSONObject tempObject = selectedCategory.getJSONObject(k);
                                long id = tempObject.getLong(BasicConstant.ID);
                                if (!categoryId.contains(id)) {
                                    selectedCategory.remove(k);
                                    k--;
                                }
                            }
                            jsonObject.put("selectedCategory",selectedCategory);
                        }
                        JsonHelperUtil.addToJSONArray(jsonArray, jsonObject);
                        break;
                    }
                }
            }
        }
        return CollectionUtils.isEmpty(jsonArray)? attrJsonArray : jsonArray;
    }

    @Override
    public JSONArray updateSearchExplain(JSONArray attrJsonArray, List<PaasFormExplainEntity> explainEntityList, Integer single, String corpid) throws XbbException {
        JSONArray jsonArray = new JSONArray();
        if (explainEntityList != null && explainEntityList.size() > 0) {
            //将formId作为key，explain作为value
            Map<Long, String> explainMap = explainEntityList.stream().collect(Collectors.toMap(paasFormExplainEntity -> paasFormExplainEntity.getFormId(), paasFormExplainEntity -> paasFormExplainEntity.getExplains()));
           outer: for (int i = 0; i < attrJsonArray.size(); i++) {
                JSONObject jsonObject = attrJsonArray.getJSONObject(i);
                if (jsonObject.getInteger(FieldAttrConstant.FIELD_TYPE).equals(FieldTypeEnum.ADDRESS.getType())) {
                    JsonHelperUtil.addToJSONArray(jsonArray, jsonObject);
                    continue;
                }
                long formId = jsonObject.getLong(StringConstant.FORM_ID);
                JSONArray explainJsonArray = JSONObject.parseArray(explainMap.get(formId));
                if (explainJsonArray == null) {
                    JsonHelperUtil.addToJSONArray(jsonArray, jsonObject);
                    continue;
                }
                for (int j = 0; j < explainJsonArray.size(); j++) {
                    JSONObject explainJsonObject = explainJsonArray.getJSONObject(j);
                    String explainAttr = explainJsonObject.getString(StringConstant.ATTR);
                    String objectAttr = jsonObject.getString(FieldAttrConstant.ORIGINALATTR);
                    boolean flag = explainAttr.equals(jsonObject.getString(StringConstant.ATTR));
                    if (single == 0 && Objects.nonNull(objectAttr)){
                        flag = objectAttr.equals(explainAttr);
                    }
                    //根据attrName匹配explain，替换
                    if (jsonObject.getString(StringConstant.ATTR).contains(EsAliasEnum.SUB_FORM.getEsAlias())
                            && (Objects.equals(FieldTypeEnum.SUB_FORM.getType(),explainJsonObject.getInteger(FieldAttrConstant.FIELD_TYPE))
                            ||Objects.equals(FieldTypeEnum.CONTACT_NUMBER.getType(),explainJsonObject.getInteger(FieldAttrConstant.FIELD_TYPE)))
                            && StringUtils.equals(jsonObject.getString(StringConstant.PARENT_ATTR),explainJsonObject.getString(StringConstant.ATTR))){
                        JSONObject tempExplainJsonObject = explainJsonObject.getJSONObject(FieldAttrConstant.SUB_FORM);
                        JSONArray subItems = tempExplainJsonObject.getJSONArray(StringConstant.ITEMS);
                        for (int p = 0; p < subItems.size(); p++) {
                            JSONObject tempObject = subItems.getJSONObject(p);
                            if ((tempObject.getString(StringConstant.PARENT_ATTR)+ StringConstant.POINT + tempObject.getString(StringConstant.ATTR)).equals(jsonObject.getString(StringConstant.ATTR))) {
                                jsonObject.put(StringConstant.ATTR_NAME,tempObject.getString(StringConstant.ATTR_NAME));
                                jsonObject.put(StringConstant.ITEMS,tempObject.getJSONArray(StringConstant.ITEMS));
                                JsonHelperUtil.addToJSONArray(jsonArray,jsonObject);
                                continue outer;
                            }
                        }
                    }
                    if (single == 0) {
                        if (objectAttr == null) {
                            objectAttr = jsonObject.getString(StringConstant.ATTR);
                        }
                        if (explainAttr != null && explainAttr.equals(objectAttr)) {
                            Set<String> set = explainJsonObject.keySet();
                            for (String s : set) {
                                if (StringConstant.ATTR_NAME.equals(s)){
                                    jsonObject.put(s, explainJsonObject.get(s));
                                }
                                if (StringConstant.ITEMS.equals(s)){
                                    FieldAttrEntity fieldAttrEntity = explainJsonObject.toJavaObject(FieldAttrEntity.class);
                                    chartAttrHelp.getItems(fieldAttrEntity,fieldAttrEntity.getBusinessType(),corpid,fieldAttrEntity.getFormId());
                                    jsonObject.put(s,fieldAttrEntity.getItems());
                                }
                            }
                            JsonHelperUtil.addToJSONArray(jsonArray, jsonObject);
                            break;
                        }
                    } else if (single == 1 && flag) {
                        Set<String> set = explainJsonObject.keySet();
                        for (String s : set) {
                            if (StringConstant.ATTR_NAME.equals(s)){
                                jsonObject.put(s, explainJsonObject.get(s));
                            }
                            if (StringConstant.ITEMS.equals(s)){
                                FieldAttrEntity fieldAttrEntity = jsonObject.toJavaObject(FieldAttrEntity.class);
                                chartAttrHelp.getItems(fieldAttrEntity,fieldAttrEntity.getBusinessType(),corpid,fieldAttrEntity.getFormId());
                                jsonObject.put(s,fieldAttrEntity.getItems());
                            }
                        }
                        //如果是产品分类的话，需要去重新查找数据库的产品分类信息。
                        JSONArray selectedCategory = jsonObject.getJSONArray("selectedCategory");
                        if (selectedCategory != null) {
                            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                            param.put(StringConstant.CORPID, corpid);
                            param.put(StringConstant.DEL, 0);
                            param.put("orderByStr", "sort ASC, update_time ASC ");
                            List<ProductCategoryEntity> allCay = productCategoryModel.findEntitys(param);
                            List<Long> categoryId = allCay.stream().map(ProductCategoryEntity::getId).collect(Collectors.toList());
                            for (int k = 0; k< selectedCategory.size(); k++) {
                                JSONObject tempObject = selectedCategory.getJSONObject(k);
                                long id = tempObject.getLong(BasicConstant.ID);
                                if (!categoryId.contains(id)) {
                                    selectedCategory.remove(k);
                                    k--;
                                }
                            }
                            jsonObject.put("selectedCategory",selectedCategory);
                        }
                        JsonHelperUtil.addToJSONArray(jsonArray, jsonObject);
                        break;
                    }
                }
            }
        }
        return CollectionUtils.isEmpty(jsonArray)? attrJsonArray : jsonArray;
    }

    /**
     * 自定义统计表汇总方法
     *
     * @param chartResultAggDTO
     * @return com.xbongbong.pro.statistic.result.pojo.vo.ChartResultAggVO
     * @throws XbbException
     * @author yuqian
     * @date 2019/5/14 10:11
     * @version v1.0
     * @since v1.0
     */
    @Override
    public ChartResultAggVO chartRenderResultAgg(ChartResultAggDTO chartResultAggDTO) throws XbbException {
        //查找图表列表
        Map<String, Object> map = BeanUtil.convertBean2Map(chartResultAggDTO, true);
        List<ChartEntity> list = chartCustomModel.findEntitys(map);
        ChartResultAggVO chartResultAggVO = new ChartResultAggVO();
        List<AggsBucketsPojo> aggList = new ArrayList<>();
        for (ChartEntity chartEntity : list) {
            if (chartEntity.getChartType().equals(ChartTypeEnum.DATA_QUERY_TABLE.getCode())
                    || chartEntity.getChartType().equals(ChartTypeEnum.DATA_STATISTICS_TABLE.getCode())) {
                //加入查询条件再进行汇总
                if (CollectionsUtil.isNotEmpty(chartResultAggDTO.getSearch())) {
                    List<JSONObject> searchList = new ArrayList<>();
                    for (JSONObject search : chartResultAggDTO.getSearch()) {
                        String attr = search.getString("attr");
                        Integer businessType = search.getInteger("businessType");
                        Object obj = search.get("value");
                        if (obj instanceof JSONArray) {
                            JSONArray value = (JSONArray) obj;
                            if (CollectionUtils.isNotEmpty(value)) {
                                if (ProductEnum.CATEGORY_ID.getAttr().equals(attr) && Objects.equals(XbbRefTypeEnum.PRODUCT.getCode(), businessType)) {
                                    String corpid = chartEntity.getCorpid();
                                    List<Long> subCategoryIdList = chartResultHelp.getSubCategoryIdList(corpid, value.getLong(0));
                                    search.put("value", subCategoryIdList);
                                }
                                //跳过选了区间但是只给了一个值
                                if (value.size() == 2) {
                                    JSONObject numericalJson = search.getJSONObject("numericalLimits");
                                    if (StringUtil.isEmpty(value.getString(0))) {
                                        if (numericalJson != null && numericalJson.get("min") != null) {
                                            value.set(0, numericalJson.get("min"));
                                            search.put("value", value);
                                        }
                                    } else if (StringUtil.isEmpty(value.getString(1))) {
                                        if (numericalJson != null && numericalJson.get("max") != null) {
                                            value.add(1, numericalJson.get("max"));
                                            search.put("value", value);
                                        }
                                    }
                                }
                            }
                        }
                        searchList.add(search);
                    }
                    if (CollectionsUtil.isNotEmpty(searchList)) {
                        chartEntity.setSearch(JSONArray.parseArray(JSON.toJSONString(searchList)));
                    }
                }
                getAggResult(chartResultAggDTO, aggList, chartEntity);
            }
        }
        chartResultAggVO.setAggList(aggList);
        return chartResultAggVO;
    }

    private void getAggResult(ChartResultAggDTO chartResultAggDTO, List<AggsBucketsPojo> aggList, ChartEntity chartEntity) throws XbbException {
        if (chartEntity.getSummaryAttr() != null && chartEntity.getSummaryAttr().size() > 0) {
            //如果驱动表是关联子产品，则使用其主业务的数据权限
            JSONObject jsonObject = chartEntity.getDriverSources();
            SlaveSourcePojo driverSourcePojo = JSON.toJavaObject(jsonObject, SlaveSourcePojo.class);
            Integer driverBusinessType = driverSourcePojo.getBusinessType();
            BIProductReformEnum biProductReformEnum = BIProductReformEnum.getEnumByProductBusinessType(driverBusinessType);
            //如果驱动表是关联子产品，则使用其主业务的数据权限
            driverBusinessType = biProductReformEnum == null ? driverBusinessType : biProductReformEnum.getBusinessType();
            TransmittableThreadLocalUtil.setValue(driverSourcePojo.getSaasMark(), driverBusinessType, driverSourcePojo.getMenuId(), null);
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            SearchRequest searchRequest = new SearchRequest();
            BoolQueryBuilder boolQueryBuilder = boolQuery();
            customHelp.chartDataEsQuery(chartEntity, sourceBuilder, boolQueryBuilder, searchRequest, chartResultAggDTO, false);
            //拼装筛选条件
            boolean hasIntersection = EsUtil.parseConditionIntersection(boolQueryBuilder, chartEntity, false);
            customHelp.customIndexQueryDefaultFilter(chartEntity, boolQueryBuilder);
            Map<String, FieldAttrPojo> fieldMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<String, String> param = countAttrAssemble(chartEntity.getSummaryAttr(), chartEntity.getFormIdAttr(), sourceBuilder, fieldMap, EsUtil.getSingle(chartEntity));
            searchRequest.source(sourceBuilder);
            Aggregations aggregations = null;
            //ES查询表的数据
            if (hasIntersection) {
                // 执行语句获取聚合结果
                aggregations = xbbElasticsearchRestTemplate.query(searchRequest);
            }
            if (aggregations != null) {
                List<Aggregation> as = aggregations.asList();
                for (Aggregation a : as) {
                    FieldAttrPojo fieldAttrPojo = fieldMap.get(a.getName());
                    //金额字段展示处理
                    String result = "0.0";
                    if (Objects.nonNull(fieldAttrPojo)) {
                        Integer accuracy = fieldAttrPojo.getAccuracy();
                        accuracy = accuracy == null ? 0 : accuracy;
                        Integer percentUsed = fieldAttrPojo.getPercentUsed();
                        Integer groupingUsed = fieldAttrPojo.getGroupingUsed();
                        if (groupingUsed == null) {
                            // 金额默认千分符
                            groupingUsed = 1;
                        }
                        String valueString = "";
                        if (a instanceof Sum) {
                            Sum sum = (Sum) a;
                            valueString = sum.getValueAsString();
                        } else if (a instanceof Min) {
                            Min min = (Min) a;
                            valueString = min.getValueAsString();
                        } else if (a instanceof Max) {
                            Max max = (Max) a;
                            valueString = max.getValueAsString();
                        } else if (a instanceof Avg) {
                            Avg avg = (Avg) a;
                            valueString = avg.getValueAsString();
                        } else if (a instanceof ValueCount) {
                            ValueCount valueCount = (ValueCount) a;
                            valueString = valueCount.getValueAsString();
                        }
                        result = attrDecimalPrecisionHelper.getNumberFormat(valueString, accuracy, groupingUsed, percentUsed);
                    }
                    AggsBucketsPojo aggsBucketsPojo = new AggsBucketsPojo(param.get(a.getName()), result);
                    aggList.add(aggsBucketsPojo);
                }
            }
        }
    }

    /**
     * webSocket统计专用请求接口
     * <p>
     * }  *
     *
     * @param socketResultDTO
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartResultVO
     * @throws XbbException
     * @author youli.chen
     * @date 2019/2/13 13:56
     * @version v1.0
     * @since v1.0
     */
    @Override
    public SocketReckonVO socketReckon(SocketResultDTO socketResultDTO) throws XbbException {
        UserEntity userEntity = BeanUtil.copyProperties(socketResultDTO.getLoginUser(), UserEntity.class, false);
        //封装chartResultPojo
        ChartResultDTO chartResultDTO = new ChartResultDTO();
        BeanUtil.copyProperties(socketResultDTO, chartResultDTO);
        ChartResultPojo chartResultPojo = chartDtoHelp.getChartResultPojo4SystemFull(userEntity, chartResultDTO);

        ChartResultDetailVO chartResultDetailVO = new ChartResultDetailVO();
        //把图表置入参数
        chartResultPojo.setSystemCodeEnum(SystemCodeEnum.OWN_CALL_OUTBOUND);
        crmCallLogResult.getTarget(chartResultPojo, chartResultDetailVO);

        List<List<ResultDataTableVO>> chartList = chartResultDetailVO.getTable().getData();

        SocketReckonVO socketReckonVO = new SocketReckonVO();
        socketReckonVO.setData(chartList);
        return socketReckonVO;
    }

    /**
     * 获取简报看板，遗忘提醒，客户关怀数据
     *
     * @param chartResultDTO 图表id数组，筛选的部门id/筛选的员工id，时间筛选参数
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartResultVO
     * @author 徐俊杰
     * @date 2019/3/11 15:43
     * @since v1.0
     */
    @Override
    public ChartResultValueVO chartResultValue(ChartResultDTO chartResultDTO) throws XbbException {
        //同时查询系统、自定义图表
        List<ChartEntity> list = ChartAnalysisFactory.getChartStrategyService(StatisticsTypeEnum.ALL.getCode()).getChartList(chartResultDTO);
        if (list == null || list.size() == 0) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224012, StatisticsServicesErrorCodeEnum.API_ERROR_224012.getMsg());
        }
        UserEntity userEntity = BeanUtil.copyProperties(chartResultDTO.getLoginUser(), UserEntity.class, false);
        ChartResultPojo chartResultPojo = chartDtoHelp.getChartResultPojo4Base(userEntity, chartResultDTO);
        //万元开关是否开启
        boolean thousandSwitch = companyConfigModel.hasBeenEnable(chartResultDTO.getCorpid(), CompanyConfigEnum.THOUSAND_SWITCH.getAlias(), "1");
        chartResultPojo.setThousandSwitch(thousandSwitch);
        //statisticsType_图表id---图表信息
        Map<String, Object> chartMap = new HashMap<>(list.size());
        // 获取当前是否是英文版,英文版不支持单位
        Boolean isEnglish = false;
        if (Objects.equals(LocaleContextHolder.getLocale().getLanguage(), I18nStringConstant.ENGLISH_LANGUAGE)) {
            isEnglish = true;
        }
        boolean bigData = commonHelp.checkBlacklistBigDataCorp(chartResultDTO.getCorpid());
        List<ChartResultValueDetailVO> chartResultValueDetailList = new ArrayList<>();
        //用于封装最后返回的list的VO
        ChartResultValueVO chartResultValueVO = new ChartResultValueVO();
        //TODO  改成异步   12个值有可能是独立的，有可能在计算第二个的时候接口已经断掉了                       2019年4月12日21:34:12
        for (ChartEntity chartEntity : list) {
            if (Objects.equals(chartEntity.getStatisticsType(), StatisticsTypeEnum.CUSTOM_STATISTIC.getCode())) {
                JSONObject jsonObject = chartEntity.getDriverSources();
                SlaveSourcePojo driverSourcePojo = JSON.toJavaObject(jsonObject, SlaveSourcePojo.class);
                TransmittableThreadLocalUtil.setValue(driverSourcePojo.getSaasMark(), driverSourcePojo.getBusinessType(), driverSourcePojo.getMenuId(), chartResultDTO.getDistributorMark());
            } else {
                String systemCode = chartEntity.getSystemCode();
                String[] codeArray = systemCode.split("_");
                TransmittableThreadLocalUtil.setValue(SaasMarkEnum.SAAS.getCode(), Integer.valueOf(codeArray[0]), null, chartResultDTO.getDistributorMark());
            }
            //把图表置入参数
            chartResultPojo.setChartEntity(chartEntity);
            //封装每个图表对应的回参
            ChartResultValueDetailVO chartResultValueDetailVO = new ChartResultValueDetailVO();
            try {
                if (!bigData) {
                    //公司数据大的不计算统计结果
                    chartResultValueDetailVO = getResultValue(chartEntity, chartResultPojo);
                }
            } catch (Exception e) {
                LOG.info("ChartResultServiceImpl.getResultValue error" + "chart id" + chartEntity.getId() + "corpid" + chartEntity.getCorpid(), e);
            }
            if (isEnglish){
                chartResultValueDetailVO.setUnit("");
            }
            // 系统指标注释取枚举 自定义取数据库
            JSONObject belongAttr = chartEntity.getBelongAttr();
            JSONObject timeAttr = chartEntity.getTimeAttr();
            Integer statisticsType = chartEntity.getStatisticsType();
            String systemCode = chartEntity.getSystemCode();
            Map<String,Object> info = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            if (Objects.equals(statisticsType,StatisticsTypeEnum.SYSTEM_STATISTIC.getCode())){
                SystemCodeAnnotateEnum codeEnum = SystemCodeAnnotateEnum.getByCode(systemCode);
                info.put("belongAttr",codeEnum.getBelongAttr());
                info.put("timeAttr",codeEnum.getTimeAttr());
                info.put("timeRange",codeEnum.getTimeRange());
                info.put("include",codeEnum.getInclude());
                if (Objects.equals(systemCode,SystemCodeAnnotateEnum.PRODUCT_COST_BOARD.getSystemCode())){
                    info.put("warehouseCost",SystemCodeAnnotateEnum.PRODUCT_COST_BOARD.getWarehouseCost());
                } else if (StringUtil.isNotEmpty(codeEnum.getMemo())) {
                    info.put("memo", codeEnum.getMemo());
                }
            } else if (Objects.equals(statisticsType,StatisticsTypeEnum.CUSTOM_STATISTIC.getCode())){
                info.put("belongAttr",Objects.nonNull(belongAttr) ? belongAttr.getString("attrName") : "");
                info.put("timeAttr",Objects.nonNull(belongAttr) ? timeAttr.getString("attrName") : "");
            }
            chartResultValueDetailVO.setInfo(info);
            chartResultValueDetailList.add(chartResultValueDetailVO);
            String key = String.format(SymbolConstant.UNDERLINE_PLACE, chartEntity.getStatisticsType(), chartEntity.getId());
            chartMap.put(key, chartResultValueDetailVO);
        }
        List<ChartResultValueDetailVO> sortList = chartResultHelp.sortChartList(chartResultDTO, chartMap, chartResultValueDetailList);
        chartResultValueVO.setChartList(sortList);
        return chartResultValueVO;
    }

    @Override
    public ChartResultPkVO chartResultPk(ChartResultDTO chartResultDTO) throws XbbException {
        UserEntity userEntity = BeanUtil.copyProperties(chartResultDTO.getLoginUser(), UserEntity.class, false);
        //查找图表列表
        Map<String, Object> map = BeanUtil.convertBean2Map(chartResultDTO, true);
        //获取pk类型的图表
        map.put("chartType", ChartTypeEnum.PK.getCode());
        List<ChartEntity> list = chartModel.findEntitys(map);
        if (list == null || list.size() == 0) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224022, StatisticsServicesErrorCodeEnum.API_ERROR_224022.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.REQUEST_PK_LIST_NOT_EXIST));
        }
        //封装pk参数pojo
        ChartResultPkPojo chartResultPkPojo = chartDtoHelp.getChartResultPojo4Pk(userEntity, chartResultDTO);
        //statisticsType_图表id---图表信息
        Map<String, Object> chartMap = new HashMap<>(list.size());
        List<ChartResultPkDetailVO> chartResultPkDetailVoList = new ArrayList<>();
        for (ChartEntity chartEntity : list) {
            SystemCodeEnum systemCodeEnum = SystemCodeEnum.getByCode(chartEntity.getSystemCode());
            if (systemCodeEnum == null) {
                continue;
            }
            //把系统枚举systemCodeEnum置入chartResultPojo
            chartResultPkPojo.setSystemCodeEnum(systemCodeEnum);
            chartResultPkPojo.setChartEntity(chartEntity);
            // 获取pk榜离职人员展示设置
            Boolean pkLeave = companyConfigModel.hasBeenEnable(chartResultDTO.getCorpid(), CompanyConfigEnum.PK_LEAVE.getAlias(), "1");
            chartResultPkPojo.setPkLeave(pkLeave);
            //封装每个图表对应的回参
            ChartResultPkDetailVO chartResultPkDetailVO = (ChartResultPkDetailVO) chartResult.getResult4Pk(userEntity, systemCodeEnum.getXbbRefTypeEnum(), chartResultPkPojo);
            //图表的其他参数（结果值以外）
            BeanUtil.copyProperties(chartEntity, chartResultPkDetailVO);
            //如果pkData为null则放入一个空数组，防止返回时没有这个字段
            List<PkInfoPojo> pkData = chartResultPkDetailVO.getPkData();
            if (pkData == null) {
                chartResultPkDetailVO.setPkData(new ArrayList<>());
            }
            chartResultPkDetailVoList.add(chartResultPkDetailVO);
            String key = String.format(SymbolConstant.UNDERLINE_PLACE, chartEntity.getStatisticsType(), chartEntity.getId());
            chartMap.put(key, chartResultPkDetailVO);
        }
        //用于封装最后返回的list的VO
        ChartResultPkVO chartResultPkVO = new ChartResultPkVO();
        List<ChartResultPkDetailVO> sortList = chartResultHelp.sortChartList(chartResultDTO, chartMap, chartResultPkDetailVoList);
        chartResultPkVO.setChartList(sortList);
        return chartResultPkVO;
    }

    /**
     * 获取pk榜范围设置pk结果
     *
     * @param chartResultDTO 请求参数
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartResultPkVO
     * @throws XbbException
     * @author youli.chen
     * @date 2020/9/9 16:47
     * @version v1.0
     * @since v1.0
     */
    @Override
    public ChartResultPkVO chartResultRulePk(ChartResultDTO chartResultDTO) throws XbbException {
        // 用工厂获取图表
        //根据chartIdIn同时获取系统、自定义图表  - 移动端可能同时存在系统、自定义一起请求的情况（分类和web端展示不一致）
        List<ChartEntity> list = ChartAnalysisFactory.getChartStrategyService(chartResultDTO.getStatisticsType()).getPkChartList(chartResultDTO);
        if (list == null || list.size() == 0) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224022, I18nMessageUtil.getMessage(I18nStringConstant.REQUEST_PK_LIST_NOT_EXIST));
        }
        UserEntity userEntity = BeanUtil.copyProperties(chartResultDTO.getLoginUser(), UserEntity.class, false);
        Integer tempTop = chartResultDTO.getTop();
        //封装pk参数pojo
        ChartResultPkPojo chartResultPkPojo = chartDtoHelp.getChartResultRulePojo4Pk(userEntity, chartResultDTO, list);

        //statisticsType_图表id---图表信息
        Map<String, Object> chartMap = new HashMap<>(list.size());
        List<ChartResultPkDetailVO> chartResultPkDetailVoList = new ArrayList<>();
        boolean bigData = commonHelp.checkBlacklistBigDataCorp(chartResultDTO.getCorpid());
        for (ChartEntity chartEntity : list) {
            //每个pk榜对应的参与员工
            List<String> userIdIn = chartResultPkPojo.getChartIdUserListMap().get(chartEntity.getId());
            List<String> canSeeUserIdIn = userIdIn == null ? chartResultPkPojo.getUserIdIn() : userIdIn;
            chartResultPkPojo.setUserIdIn(canSeeUserIdIn);
            //封装每个图表对应的回参
            ChartResultPkDetailVO chartResultPkDetailVO;
            // 查询当前登陆人是否在可见权限中,公司数据大的不计算统计结果
            if (!pkRuleHelp.checkLoginUserCanSee(chartEntity, userEntity) || bigData) {
                // 大数据公司打下日志
                if (bigData) {
                    LOG.info("该公司:" + chartResultDTO.getCorpid() + ",数据过大，不计算pk榜统计结果");
                }
                chartResultPkDetailVO = new ChartResultPkDetailVO();
                chartResultPkDetailVoList.add(chartResultPkDetailVO);
                String key = String.format(SymbolConstant.UNDERLINE_PLACE, chartEntity.getStatisticsType(), chartEntity.getId());
                chartMap.put(key, chartResultPkDetailVO);
                continue;
            }
            // 区分系统和自定义
            boolean custom = Objects.equals(chartEntity.getStatisticsType(), StatisticsTypeEnum.CUSTOM_STATISTIC.getCode());
            if (custom) {
                chartResultPkPojo.setChartEntity(chartEntity);
                // 处理threadLocal
                JSONObject jsonObject = chartEntity.getDriverSources();
                SlaveSourcePojo driverSourcePojo = JSON.toJavaObject(jsonObject, SlaveSourcePojo.class);
                TransmittableThreadLocalUtil.setValue(driverSourcePojo.getSaasMark(), driverSourcePojo.getBusinessType(), driverSourcePojo.getMenuId(), chartResultDTO.getDistributorMark());
                //获取数据
                chartResultPkDetailVO = getCustomResultValue4Pk(userEntity, chartEntity, chartResultPkPojo);
            } else {
                SystemCodeEnum systemCodeEnum = SystemCodeEnum.getByCode(chartEntity.getSystemCode());
                if (systemCodeEnum == null) {
                    continue;
                }
                // 把系统枚举systemCodeEnum置入chartResultPojo
                chartResultPkPojo.setSystemCodeEnum(systemCodeEnum);
                chartResultPkPojo.setChartEntity(chartEntity);

                ChartResultProService chartResultProService = chartStrategyFactory.getChartResultProService(systemCodeEnum.getXbbRefTypeEnum().getCode());
                if (Objects.isNull(chartResultProService)) {
                    chartResultProService = chartStrategyFactory.getChartResultProService(BasicConstant.ZERO);
                }
                // 获取结果
                chartResultPkDetailVO = (ChartResultPkDetailVO) chartResultProService.getResult4PkRule(userEntity, chartEntity, systemCodeEnum.getXbbRefTypeEnum(), chartResultPkPojo);
//                chartResultPkDetailVO = (ChartResultPkDetailVO) chartResult.getResult4PkRule(userEntity, chartEntity, systemCodeEnum.getXbbRefTypeEnum(), chartResultPkPojo);
                // 选了数值格式，就按数值格式的单位
                Integer numFormat = chartEntity.getNumFormat();
                if (numFormat != null) {
                    NumFormatEnum numFormatEnum = NumFormatEnum.getByCode(numFormat);
                    String unit = numFormatEnum.getUnit();
                    chartEntity.setUnit(unit);
                }
            }

            //图表的其他参数（结果值以外）
            BeanUtil.copyProperties(chartEntity, chartResultPkDetailVO);
            //如果pkData为null则放入一个空数组，防止返回时没有这个字段
            List<PkInfoPojo> pkData = chartResultPkDetailVO.getPkData();
            if (pkData == null) {
                chartResultPkDetailVO.setPkData(new ArrayList<>());
            } else {
                JSONObject explains = chartEntity.getExplains() == null ? new JSONObject() : chartEntity.getExplains();
                Boolean changeLess =  explains.getBoolean("changeless");
                Map<String, String> sortMap = null;
                if (changeLess != null && changeLess) {
                    sortMap = (Map) explains.get("sortMap");
                }
                sortMap = (chartResultDTO.getSortMap() == null || chartResultDTO.getSortMap().size() == 0) ? sortMap : chartResultDTO.getSortMap();
                if (sortMap != null && sortMap.size() > 0) {
                    for (Map.Entry<String, String> entry : sortMap.entrySet()) {
                        String key = entry.getKey();
                        String value = entry.getValue();
                        if (Objects.equals(value, "asc")) {
                            if (Objects.equals(key, "value")) {
                                pkData.sort((o1, o2) -> o2.getRank() - o1.getRank());
                            } else {
                                pkData.sort(Comparator.comparingInt(PkInfoPojo::getRank));
                            }
                        } else if (Objects.equals(value, "desc")) {
                            if (Objects.equals(key, "value")) {
                                pkData.sort(Comparator.comparingInt(PkInfoPojo::getRank));
                            } else {
                                pkData.sort((o1, o2) -> o2.getRank() - o1.getRank());
                            }
                        } else {
                            break;
                        }
                    }
                    chartResultPkDetailVO.setPkData(pkData);
                }
            }
            // 公司top3 + 数据权限
            if(Objects.equals(chartEntity.getPowerType(),BasicConstant.TWO)){
                if(CollectionsUtil.isNotEmpty(pkData) && chartResultDTO.getPkType().equals(1)){
                    pkData = chartPkRuleHelp.filterResults(chartResultDTO,tempTop,userEntity,chartEntity,pkData);
                    chartResultPkDetailVO.setPkData(pkData);
                }
                // 返回给前端首页的是否开启“全公司Top3”开关
                chartResultPkDetailVO.setChooseTop3Flag(true);
            }

            JSONArray category = chartEntity.getCategory();
            if(category != null){
                List<Long> categoryIdList = JSONObject.parseArray(category.toJSONString(), Long.class);
                if (categoryIdList.size() >= 2) {
                    chartResultPkDetailVO.setCategoryId(categoryIdList.get(1));
                }else{
                    chartResultPkDetailVO.setCategoryId(categoryIdList.get(0));
                }
            }
            chartResultPkDetailVO.setChooseTemp(BasicConstant.ZERO);
            Integer chartType = chartEntity.getChartType();
            String systemCode = chartEntity.getSystemCode();
            if(Objects.equals(chartType, ChartTypeEnum.PK.getCode()) || Objects.equals(chartType, ChartTypeEnum.PK_CUSTOM.getCode())){
                if(Objects.equals(systemCode, SystemCodeEnum.PK_CONTRACT_AMOUNT.getSystemCode()) || Objects.equals(systemCode, SystemCodeEnum.PK_CONTRACT_COUNT.getSystemCode()) ||
                        Objects.equals(systemCode, SystemCodeEnum.PK_CUSTOMER_ADD.getSystemCode()) || Objects.equals(systemCode, SystemCodeEnum.PK_OPPORTUNITY_ADD_COUNT.getSystemCode()) ||
                        Objects.equals(systemCode, SystemCodeEnum.PK_OPPORTUNITY_ADD_AMOUNT.getSystemCode()) || Objects.equals(systemCode, SystemCodeEnum.PK_CONTRACT_PROFIT.getSystemCode())){
                    chartResultPkDetailVO.setChooseTemp(BasicConstant.ONE);
                }
            }
            chartResultPkDetailVoList.add(chartResultPkDetailVO);
            String key = String.format(SymbolConstant.UNDERLINE_PLACE, chartEntity.getStatisticsType(), chartEntity.getId());
            chartMap.put(key, chartResultPkDetailVO);
        }
        //用于封装最后返回的list的VO
        List<ChartResultPkDetailVO> sortList = chartResultHelp.sortChartList(chartResultDTO, chartMap, chartResultPkDetailVoList);
        ChartResultPkVO chartResultPkVO = new ChartResultPkVO();
        chartResultPkVO.setChartList(sortList);
        return chartResultPkVO;
    }

    @Override
    public ChartResultPkDetailVO chartResultPerformance(ChartResultDTO chartResultDTO) throws XbbException {
        ChartResultPkDetailVO chartResultPkDetailVO = new ChartResultPkDetailVO();
        String corpid = chartResultDTO.getCorpid();
        chartResultDTO.setPerformanceFlag(true);
        if (Objects.equals(chartResultDTO.getStatisticsType(), StatisticsTypeEnum.CUSTOM_STATISTIC.getCode())){
            // 只有旗舰版的自定义才能显示数据
            if (!packageHelp.isUltimateWithFeeType(corpid)){
                return chartResultPkDetailVO;
            }
        }
        List<ChartIdPojo> idIn = chartResultDTO.getChartIdIn();
        if (idIn.size() > 1) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224022, StatisticsServicesErrorCodeEnum.API_ERROR_224022.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.ONE_RESULT_CHART));
        }
        ResultFromEnum resultFromEnum = ResultFromEnum.getByValue(chartResultDTO.getFrom());
        if (resultFromEnum == ResultFromEnum.UNKNOWN) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224011, StatisticsServicesErrorCodeEnum.API_ERROR_224011.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.IDENTIFY_TARGET_REQUEST_SOURCE));
        }
        ChartIdPojo checkChartIdPojo = idIn.size() > 0 ? idIn.get(0) : new ChartIdPojo();
        checkChartIdPojo.setFrom(chartResultDTO.getFrom());
        UserEntity userEntity = BeanUtil.copyProperties(chartResultDTO.getLoginUser(), UserEntity.class, false);
        //查找图表列表
        Map<String, Object> map = BeanUtil.convertBean2Map(chartResultDTO, true);

        Integer statisticsType = chartResultDTO.getStatisticsType();
        boolean systemFlag = Objects.equals(statisticsType, StatisticsTypeEnum.SYSTEM_STATISTIC.getCode());
        List<Integer> chartTypeIn = ChartTypeEnum.getPerformanceChartType(statisticsType);
        map.put("chartTypeIn", chartTypeIn);

        //先不限制idIn条件，因为对于移动端的完成情况，是需要把所有的启用的图表读出来
        map.remove("idIn");

        // 工厂类获取chartList
        List<ChartEntity> allList = ChartAnalysisFactory.getChartStrategyService(statisticsType).getChartList(map);
        ChartResultPojo chartResultPojo = chartDtoHelp.getChartResultPojo4Base(userEntity, chartResultDTO);
        //标记为业绩目标（产品销量需要用到）
        chartResultPojo.setPerformancePk(true);

        //当resultFromEnum值为“hamlet”时代表千人千面请求，不在考核范围的不能过滤，而是要返回一个不在考核范围的信息
        boolean indexFlag = resultFromEnum == ResultFromEnum.HAMLET;
        //登录员工查看到的目标list
        List<ChartEntity> viewList = performanceHelp.getViewList(indexFlag, userEntity, chartResultPojo.getDataPermission(), allList);
        if (viewList == null || viewList.size() == 0) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240020, PerformanceErrorCodeEnum.API_ERROR_240020.getMsg());
        }
        //最终要获取目标和完成额的目标
        List<ChartEntity> list = getPerformanceList(checkChartIdPojo, viewList, chartResultPkDetailVO);
        if (indexFlag) {
            if (systemFlag) {
                //获取首页业绩目标在图表中心对应的分类id,系统通过alias获取一级分类
                ChartCategoryEntity entity = chartCategoryModel.getEntityByAlias(chartResultPojo.getCorpid(), ChartCategoryEnum.PERFORMANCE_FINISH_CHART.getAlias());
                chartResultPkDetailVO.setCategoryId(entity.getId());
            } else {
                //自定义获取二级分类id
                chartResultPkDetailVO.setCategoryId(list.get(0).getCategoryId4Second());
            }
        }
        // 系统目标数值格式，从PERFORMANCE_CHART中拿
        if (systemFlag) {
            ChartEntity systemChart = chartModel.getSystemChartByCode(corpid, SystemCodeEnum.PERFORMANCE_CHART);
            NumFormatEnum numFormatEnum = NumFormatEnum.getByCode(systemChart.getNumFormat());
            chartResultPojo.setNumFormat(numFormatEnum.getCode());
            chartResultPojo.setUnit(numFormatEnum.getUnit());
        }
        //处理穿透
        TimePojo timePojo = throughHelp.formatThroughTimeInfo(false, chartResultPojo.getFiscalYearTimePojo(), chartResultPojo.getStartTime(), chartResultPojo.getEndTime());
        List<PkPerforInfoPojo> perforData = new ArrayList<>();
        CompanyStructTypeEnum companyStructTypeEnum = performanceHelp.getCompanyStructTypeEnum4Must(chartResultPojo.getCompanyStructType(), chartResultPojo.getCheckedUserId(), chartResultPojo.getCheckedDepId());
        chartResultPojo.setDistributorMark(chartResultDTO.getDistributorMark());
        for (ChartEntity chartEntity : list) {
            SystemCodeEnum systemCodeEnum = SystemCodeEnum.getByCode(chartEntity.getSystemCode());
            if (systemCodeEnum == null) {
                continue;
            }
            //把系统枚举systemCodeEnum置入chartResultPojo
            chartResultPojo.setSystemCodeEnum(systemCodeEnum);
            chartResultPojo.setChartEntity(chartEntity);
            PkPerforInfoPojo pkPerforInfoPojo = getResultPerformance(indexFlag, companyStructTypeEnum, chartEntity, systemCodeEnum, chartResultPojo, timePojo);
            if (pkPerforInfoPojo != null) {
                perforData.add(pkPerforInfoPojo);
            }
        }
        chartResultPkDetailVO.setPerforData(perforData);
        return chartResultPkDetailVO;
    }

    @Override
    public ChartResultPkDetailVO chartResultPerformancePk(ChartResultPerformancePkDTO chartResultPerformancePkDTO) throws XbbException {
        UserEntity userEntity = BeanUtil.copyProperties(chartResultPerformancePkDTO.getLoginUser(), UserEntity.class, false);
        List<ChartEntity> chartList = ChartAnalysisFactory.getChartStrategyService(chartResultPerformancePkDTO.getStatisticsType()).getChartList(chartResultPerformancePkDTO);
        if (CollectionsUtil.isEmpty(chartList)) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224012, StatisticsServicesErrorCodeEnum.API_ERROR_224012.getMsg());
        }
        ChartEntity chartEntity = chartList.get(0);
        if (!Objects.equals(ChartTypeEnum.PERFORMANCE.getCode(), (chartEntity.getChartType())) && !Objects.equals(ChartTypeEnum.CUSTOMER_PERFORMANCE.getCode(), (chartEntity.getChartType()))) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224047);
        }
        //封装业绩目标参数pojo
        ChartResultPojo chartResultPojo = chartDtoHelp.getChartResultPojo4Base(userEntity, chartResultPerformancePkDTO);
        //标记为业绩目标（产品销量需要用到）
        chartResultPojo.setPerformancePk(true);
        //员工目标完成情况排行list
        List<PkPerforInfoPojo> pkPerforInfoPojoList = performancePk(userEntity, chartResultPojo, chartEntity);

        //图表的其他参数（结果值以外）
        ChartResultPkDetailVO chartResultPkDetailVO = BeanUtil.copyProperties(chartEntity, ChartResultPkDetailVO.class, false);
        chartResultPkDetailVO.setPerforData(pkPerforInfoPojoList);
        chartResultPkDetailVO.setUnit(customHelp.setUnit(chartEntity));
        return chartResultPkDetailVO;
    }

    @Override
    public PerformanceFinishVO chartResultPerformanceFinish(ChartResultBaseDTO chartResultBaseDTO) throws XbbException {
        PerformanceFinishVO finishVO = new PerformanceFinishVO();
        String corpid = chartResultBaseDTO.getCorpid();
        if (Objects.equals(chartResultBaseDTO.getStatisticsType(), StatisticsTypeEnum.CUSTOM_STATISTIC.getCode())) {
            // 自定义目标管理只有旗舰版能用
            if (!packageHelp.isUltimateWithFeeType(corpid)) {
                return finishVO;
            }
        }
        UserEntity userEntity = BeanUtil.copyProperties(chartResultBaseDTO.getLoginUser(), UserEntity.class, false);
        // 筛选的员工或部门---业绩类型：1员工的业绩 2部门的业绩
        CompanyStructTypeEnum companyStructTypeEnum = performanceHelp.getCompanyStructTypeEnum(chartResultBaseDTO.getCompanyStructType());
        Long checkedDepId = chartResultBaseDTO.getCheckedDepId();
        if (CompanyStructTypeEnum.DEPARTMENT == companyStructTypeEnum && checkedDepId == null) {
            //当筛选了部门类型时，必须得传部门id
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224020, StatisticsServicesErrorCodeEnum.API_ERROR_224020.getMsg(), I18nMessageUtil.getMessage(CommonConstant.DEPARTMENT));
        }
        //封装业绩目标参数pojo
        ChartResultPojo chartResultPojo = chartDtoHelp.getChartResultPojo4Base(userEntity, chartResultBaseDTO);
        chartResultPojo.setPage(chartResultBaseDTO.getPage());
        chartResultPojo.setPageSize(chartResultBaseDTO.getPageSize());
        //标记为业绩目标（产品销量需要用到）
        chartResultPojo.setPerformancePk(true);

        // 系统目标数值格式，从PERFORMANCE_CHART中拿
        if (Objects.equals(chartResultBaseDTO.getStatisticsType(), StatisticsTypeEnum.SYSTEM_STATISTIC.getCode())) {
            ChartEntity systemChart = chartModel.getSystemChartByCode(corpid, SystemCodeEnum.PERFORMANCE_CHART);
            NumFormatEnum numFormatEnum = NumFormatEnum.getByCode(systemChart.getNumFormat());
            chartResultPojo.setNumFormat(numFormatEnum.getCode());
            chartResultPojo.setUnit(numFormatEnum.getUnit());
        }
        chartResultPojo.setDistributorMark(chartResultBaseDTO.getDistributorMark());
        switch (companyStructTypeEnum) {
            case USER:
                finishVO = performanceFinish4User(userEntity, chartResultPojo);
                break;
            case DEPARTMENT:
                finishVO = performanceFinish4Dep(userEntity, chartResultPojo);
                break;
            default:
                throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224020, StatisticsServicesErrorCodeEnum.API_ERROR_224020.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.PERFORMANCE_TYPE));
        }

        return finishVO;
    }

    /**
     * 员工呼出/呼入统计
     *
     * @param chartResultCallStatisticsDTO
     * @return com.xbongbong.paas.pojo.vo.CallStatisticsVO
     * @throws XbbException
     * @author zcp
     * @date 2019/4/1 19:22
     * @version v1.0
     * @since v1.0
     */
    @Override
    public CallStatisticsVO chartResultCallStatistics(ChartResultCallStatisticsDTO chartResultCallStatisticsDTO) throws XbbException {
        UserEntity userEntity = BeanUtil.copyProperties(chartResultCallStatisticsDTO.getLoginUser(), UserEntity.class, false);
        //塞入map
        Map<String, Object> map = BeanUtil.convertBean2Map(chartResultCallStatisticsDTO, true);
        List<ChartEntity> list = chartModel.findEntitys(map);
        if (list == null || list.size() == 0) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224012, StatisticsServicesErrorCodeEnum.API_ERROR_224012.getMsg());
        }

        ChartEntity chartEntity = list.get(0);
        CallLogTypeEnum callLogTypeEnum = null;
        if(Objects.equals(chartEntity.getSystemCode(), SystemCodeEnum.CALL_STAFF_INBOUND.getSystemCode())){
            callLogTypeEnum = CallLogTypeEnum.INBOUND;
        }
        if(Objects.equals(chartEntity.getSystemCode(), SystemCodeEnum.CALL_STAFF_OUTBOUND.getSystemCode())){
            callLogTypeEnum = CallLogTypeEnum.OUTBOUND;
        }

        //封装参数pojo
        ChartResultPojo chartResultPojo = chartDtoHelp.getChartResultPojo4Base(userEntity, chartResultCallStatisticsDTO);

        String sortAttr = chartResultCallStatisticsDTO.getSortAttr();
        boolean sortType = false;
        String sort = chartResultCallStatisticsDTO.getSortType();
        if(sort == null){
            sortType = false;
        } else if(Objects.equals(sort, SortOrder.DESC.toString())){
            sortType = false;
        } else if(Objects.equals(sort, SortOrder.ASC.toString())){
            sortType = true;
        }

        CallStatisticsVO callVO;
        switch (callLogTypeEnum) {
            case INBOUND:
                callVO = callStatistics4User(userEntity, chartResultPojo, sortAttr, sortType, true);
                break;
            case OUTBOUND:
                callVO = callStatistics4User(userEntity, chartResultPojo, sortAttr, sortType, false);
                break;
            default:
                throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224020, StatisticsServicesErrorCodeEnum.API_ERROR_224020.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.CALL_TYPE));
        }
        callVO.setChartId(chartEntity.getId());
        return callVO;
    }

    /**
     * 员工呼出/呼入统计总计
     *
     * @param chartResultCallStatisticsDTO
     * @return com.xbongbong.paas.pojo.vo.CallStatisticsVO
     * @throws XbbException
     * @author zcp
     * @date 2019/4/1 19:22
     * @version v1.0
     * @since v1.0
     */
    @Override
    public CallStatisticsVO chartResultCallStatisticsTotal(ChartResultCallStatisticsDTO chartResultCallStatisticsDTO) throws XbbException {
        UserEntity userEntity = BeanUtil.copyProperties(chartResultCallStatisticsDTO.getLoginUser(), UserEntity.class, false);
        //塞入map
        Map<String, Object> map = BeanUtil.convertBean2Map(chartResultCallStatisticsDTO, true);
        List<ChartEntity> list = chartModel.findEntitys(map);
        if (list == null || list.size() == 0) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224012, StatisticsServicesErrorCodeEnum.API_ERROR_224012.getMsg());
        }

        ChartEntity chartEntity = list.get(0);
        CallLogTypeEnum callLogTypeEnum = null;
        if(Objects.equals(chartEntity.getSystemCode(), SystemCodeEnum.CALL_STAFF_INBOUND.getSystemCode())){
            callLogTypeEnum = CallLogTypeEnum.INBOUND;
        }
        if(Objects.equals(chartEntity.getSystemCode(), SystemCodeEnum.CALL_STAFF_OUTBOUND.getSystemCode())){
            callLogTypeEnum = CallLogTypeEnum.OUTBOUND;
        }

        //封装参数pojo
        ChartResultPojo chartResultPojo = chartDtoHelp.getChartResultPojo4Base(userEntity, chartResultCallStatisticsDTO);

        CallStatisticsVO callVO;
        switch (callLogTypeEnum) {
            case INBOUND:
                callVO = callStatistics4UserTotal(userEntity, chartResultPojo, true);
                break;
            case OUTBOUND:
                callVO = callStatistics4UserTotal(userEntity, chartResultPojo,false);
                break;
            default:
                throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224020, StatisticsServicesErrorCodeEnum.API_ERROR_224020.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.CALL_TYPE));
        }
        callVO.setChartId(chartEntity.getId());
        return callVO;
    }

    @Override
    public ChartResultDetailVO gitDiyResult(DiyResultDTO diyResultDTO) throws XbbException {
        return gitDiyResult(diyResultDTO.getChartEntity(), diyResultDTO.getChartResultPojo(), diyResultDTO.getChartResultDetailVO());
    }

    @Override
    public SalesReportVO chartResultSalesReport(SalesReportPojo salesReportPojo) throws XbbException {
        ChartResultPojo chartResultPojo = BeanUtil.copyProperties(salesReportPojo, ChartResultPojo.class, false);
        //只读取一次该员工的数据权限，以及下属员工ids
        chartDtoHelp.setChartResultBaseInfo(chartResultPojo, salesReportPojo.getLogUserEntity());

        /**
         key 为指标alias，@see ReportTargetEnum枚举的alias
         value 为统计出的该指标的总额，格式为{“day”:0,”month”:0}
         */
        Map<String, JSONObject> reportTargetMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        //-----------先计算月额
        chartResultPojo.setStartTime(salesReportPojo.getMonthStartTime());
        chartResultPojo.setEndTime(salesReportPojo.getMonthEndTime());
        boolean emptyFlag4Month = getSalesReport(ReportTypeEnum.MONTH, chartResultPojo, reportTargetMap);
        //-----------再计算日/周额
        chartResultPojo.setStartTime(salesReportPojo.getDayStartTime());
        chartResultPojo.setEndTime(salesReportPojo.getDayEndTime());
        boolean emptyFlag4Day = getSalesReport(ReportTypeEnum.DAY, chartResultPojo, reportTargetMap);
        //-----------如果都没有值，则不入targetLog库
        if (emptyFlag4Month && emptyFlag4Day) {
            //如果月、日（周）都为空，则返回null
            LOG.info("ChartResultServiceImpl.chartResultSalesReport return null, corpid=" + salesReportPojo.getCorpid());
            return null;
        }
        //-----------统计结果入targetLog库
        salesReportPojo.setReportTargetMap(reportTargetMap);
        //把该user的指标存库
        commonHelp.saveSalesReport(salesReportPojo);
        //用于封装最后返回的VO
        SalesReportVO salesReportVo = new SalesReportVO();
        return salesReportVo;
    }

    @Override
    public FundFlowVO getFundFlow(ChartResultDTO chartResultDTO) throws XbbException {
        FundFlowVO fundFlowVO = new FundFlowVO();
        UserVO loginUser = chartResultDTO.getLoginUser();
        String corpid = chartResultDTO.getCorpid();
        //资金账户相关数据
        boolean adminOrBoss = loginUser.isAdminOrBoss();
        if (!adminOrBoss || !Objects.equals(chartResultDTO.getCheckedDepId(), 1L)) {
            //只有全公司数据权限才可以看到资金账户余额
            return fundFlowVO;
        }
        fundFlowVO.setAccountType(BasicConstant.ONE);
        Long accountId = chartResultDTO.getAccountId();
        //accountId 传空时处理
        accountId = accountId == null ? Long.valueOf(0) : accountId;
        chartResultDTO.setAccountId(accountId);
        List<Long> ids = fundHelp.dealWithFundAccount(accountId, corpid);

        // 数值格式处理，由于账户资金的数据不来自chart表，用前端传来的chartId查询
        Integer numFormat = NumFormatEnum.DEFAULT.getCode();
        List<ChartEntity> chartList = ChartAnalysisFactory.getChartStrategyService(StatisticsTypeEnum.ALL.getCode()).getChartList(chartResultDTO);
        if (CollectionsUtil.isNotEmpty(chartList)) {
            ChartEntity chartEntity = chartList.get(0);
            numFormat = chartEntity.getNumFormat();
        }
        NumFormatEnum numFormatEnum = NumFormatEnum.getByCode(numFormat);
        String unit = NumFormatEnum.getByCode(numFormat).getUnit();

        //资金账户相关数据
        String amountStr;
        if (Objects.equals(accountId, FundStatisticsConstant.ALL_ACCOUNT)) {
            //获取该公司资金账户的余额总和
            double sum = fundAccountModel.sumBalanceByCorpid(corpid);
            amountStr = ChartResultUtil.formatValue2Double(false, ValueTypeEnum.VALUE_MONEY, false, sum, numFormatEnum, false);
        } else {
            //当前账户余额-金额
            FundAccountEntity fundAccount = fundAccountModel.getByIdCorpid(accountId, corpid);
            double amount = fundAccount == null ? 0d : fundAccount.getAmount().doubleValue();
            amountStr = ChartResultUtil.formatValue2Double(false, ValueTypeEnum.VALUE_MONEY, false, amount, numFormatEnum, false);
        }
        //当前账户余额
        IndexVO accountBalance = new IndexVO(amountStr, I18nMessageUtil.getMessage(FundStatisticsConstant.NOW_ACCOUNT_BALANCE), AccessLinkEnum.FUND_ACCOUNT.getIcon(), AccessLinkEnum.FUND_ACCOUNT.getColor(), unit);

//        TODO 以下方法需优化，实现方法不优雅，且规则不符合新的产品需求 -- by 资金二期 zcp
        List<FundFlowDetailVO> fundDetailList = new ArrayList<>();
        UserEntity userEntity = BeanUtil.copyProperties(loginUser, UserEntity.class, false);
        ChartResultPojo chartResultPojo = chartDtoHelp.getChartResultPojo4Base(userEntity, chartResultDTO);
        chartResultPojo.setAccountIdList(ids);
        // 因为单位需要前置置入，不然单位转换的时候会使用默认单位默认
        chartResultPojo.setNumFormat(numFormatEnum.getCode());
        //回款
        FundFlowInfoPojo fundFlowInfoPojo = fundResult.getFundFlowInfoPojo(chartResultPojo);
        //回款
        double paymentSheetAmount = fundFlowInfoPojo.getPaymentSheetAmount();
        String paymentSheetAmountStr = fundFlowInfoPojo.getPaymentSheetAmountStr();
        //付款
        double paySheetAmount = fundFlowInfoPojo.getPaySheetAmount();
        String paySheetAmountStr = fundFlowInfoPojo.getPaySheetAmountStr();
        //净流水
        String flowAmountStr = fundFlowInfoPojo.getFlowAmountStr();
        FundFlowDetailVO fundFlowPayment = new FundFlowDetailVO(paymentSheetAmount, paymentSheetAmountStr, FundFlowEnum.PAYMENT.getName(), FundFlowEnum.PAYMENT.getType(), null, unit);
        fundDetailList.add(fundFlowPayment);
        //付款
        FundFlowDetailVO fundFlowPay = new FundFlowDetailVO(paySheetAmount, paySheetAmountStr, FundFlowEnum.PAY.getName(), FundFlowEnum.PAY.getType(), null, unit);
        fundDetailList.add(fundFlowPay);
        fundFlowVO.setFundDetail(fundDetailList);

        //流水塞入上部
        IndexVO accountFlow = new IndexVO(flowAmountStr, I18nMessageUtil.getMessage(FundStatisticsConstant.ACCOUNT_FLOW), AccessLinkEnum.FUND_ACCOUNT.getIcon(), AccessLinkEnum.FUND_ACCOUNT.getColor(), unit);
        List<IndexVO> fundTop = Arrays.asList(accountBalance, accountFlow);
        fundFlowVO.setFundTop(fundTop);
        return fundFlowVO;
    }

    /**
     * 获取图表统计结果（系统、自定义图表）
     *
     * @param chartEntity     图表实体
     * @param chartResultPojo 请求系统指标接口需要用到的pojo类（内部存系统指标统计时需要的参数）
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartResultDetailVO
     * @throws XbbException
     * @author zcp
     * @date 2019/2/14 10:58
     * @version v1.0
     * @since v1.0
     */
    public ChartResultDetailVO getResult(ChartEntity chartEntity, ChartResultPojo chartResultPojo, List<PaasFormExplainEntity> explainEntityList, List<JSONObject> searchObjectList,boolean penetrateFlag) throws XbbException {
        ChartResultDetailVO chartResultDetailVO = new ChartResultDetailVO();
        chartResultDetailVO.setChartId(chartEntity.getId());
        chartResultDetailVO.setChartEntity(chartEntity);
        StatisticsTypeEnum statisticsTypeEnum = StatisticsTypeEnum.getByCode(chartEntity.getStatisticsType());
        switch (statisticsTypeEnum) {
            case SYSTEM_STATISTIC:
                SystemCodeEnum systemCodeEnum = SystemCodeEnum.getByCode(chartEntity.getSystemCode());
                if (systemCodeEnum != null) {
                    String systemCode = chartEntity.getSystemCode();
                    String[] codeArray = systemCode.split("_");
                    TransmittableThreadLocalUtil.setValue(SaasMarkEnum.SAAS.getCode(), Integer.valueOf(codeArray[0]), null, null);
                    //把系统枚举systemCodeEnum置入chartResultPojo
                    chartResultPojo.setSystemCodeEnum(systemCodeEnum);
                    // 数值格式
                    if (Objects.equals(systemCodeEnum.getHasAmount(), 1)) {
                        Integer numFormat = chartEntity.getNumFormat();
                        chartResultPojo.setNumFormat(numFormat);
                        NumFormatEnum numFormatEnum = NumFormatEnum.getByCode(numFormat);
                        String unit = numFormatEnum.getUnit();
                        chartResultPojo.setUnit(unit);
                        chartEntity.setUnit(unit);
                    }
                    //计算结果--系统图表的信息也在计算结果内部置入ChartResultDetailVO的子对象内
                    ChartResultProService chartResultProService = chartStrategyFactory.getChartResultProService(systemCodeEnum.getXbbRefTypeEnum().getCode());
                    if (Objects.isNull(chartResultProService)){
                        chartResultProService = chartStrategyFactory.getChartResultProService(BasicConstant.ZERO);
                    }
                    chartResultDetailVO = (ChartResultDetailVO) chartResultProService.getResult4System(ReturnTypeEnum.ARRAY_RETURN, systemCodeEnum.getXbbRefTypeEnum(), chartResultPojo, chartResultDetailVO);
                    sortSystemChart(chartEntity, chartResultPojo, chartResultDetailVO);
                }
                break;
            case CUSTOM_STATISTIC:
                JSONObject jsonObject = chartEntity.getDriverSources();
                SlaveSourcePojo driverSourcePojo = JSON.toJavaObject(jsonObject, SlaveSourcePojo.class);
                Integer driverBusinessType = driverSourcePojo.getBusinessType();
                BIProductReformEnum biProductReformEnum = BIProductReformEnum.getEnumByProductBusinessType(driverBusinessType);
                //如果驱动表是关联子产品，则使用其主业务的数据权限
                driverBusinessType = biProductReformEnum == null ? driverBusinessType : biProductReformEnum.getBusinessType();
                TransmittableThreadLocalUtil.setValue(driverSourcePojo.getSaasMark(), driverBusinessType, driverSourcePojo.getMenuId(), null);
                //单表还是多表
                Integer single = chartEntity.getSingle();
                //关联数据
                if(!EsUtil.getSingle(chartEntity)){
                    single = 0;
                }
                updateExplainChartAttr(chartEntity, explainEntityList, searchObjectList, single);
                //处理查询条件
                chartResultHelp.searchCheck(searchObjectList,chartEntity,chartResultPojo);
                //图表使用数量的限制
                chartLimitService.chartDataLimit(chartEntity.getCorpid(), chartEntity.getDriverSources(), chartEntity.getSlaveSources(),chartEntity.getSingle());
                if(!chartLimitService.getCkFlag() || Objects.equals(chartEntity.getChartType(),ChartTypeEnum.PK_CUSTOM.getCode())){
                    return gitDiyResult(chartEntity, chartResultPojo, chartResultDetailVO,penetrateFlag);
                }

                DiyResultDTO diyResultDTO = new DiyResultDTO();
                BeanUtil.copyProperties(chartResultPojo, diyResultDTO, true);
                diyResultDTO.setChartEntity(chartEntity);
                diyResultDTO.setChartResultDetailVO(chartResultDetailVO);
                diyResultDTO.setChartResultPojo(chartResultPojo);
                XbbResponse<Object> diyResponse = null;
                try {
                    // 获取缓存key
                    String key = chartResultHelp.getChartCacheKey(chartEntity,chartResultPojo,diyResultDTO);
                    // 从缓存获取存在的数据
                    String diyResponseStr = paasRedisHelper.getValue(RedisPrefixConstant.FEIGN_CK_RESULT, key);
                    if(StringUtil.isNotEmpty(diyResponseStr)){
                        diyResponse = JSONObject.parseObject(diyResponseStr,XbbResponse.class,Feature.OrderedField);
                    }else {
                        diyResponse = diyResultFeignClient.getCkResult(diyResultDTO);
                        paasRedisHelper.setValue(RedisPrefixConstant.FEIGN_CK_RESULT, key,diyResponse,RedisTimeConstant.TINY_DURATION);
                    }
                } catch (Exception e) {
                    LOG.error("",e);
                }
                if (diyResponse != null ) {
                    if(diyResponse.isSuccess()){
                        chartResultDetailVO = JSONObject.parseObject(JSON.toJSONString(diyResponse.getResult(), SerializerFeature.DisableCircularReferenceDetect), ChartResultDetailVO.class);
                    }else {
                        throw new XbbException(diyResponse.getCode(),diyResponse.getMsg());
                    }
                }
                break;
            default:
                break;
        }
        return chartResultDetailVO;
    }

    private void updateExplainChartAttr(ChartEntity chartEntity, List<PaasFormExplainEntity> explainEntityList, List<JSONObject> searchObjectList, Integer single) throws XbbException {
        JSONArray displayAttr = chartEntity.getDisplayAttr();
        JSONArray rowGroupAttr = chartEntity.getRowGroupAttr();
        JSONArray colGroupAttr = chartEntity.getColGroupAttr();
        JSONArray chartClassify = chartEntity.getChartClassify();
        JSONArray chartSeries = chartEntity.getChartSeries();
        JSONArray summaryAttr = chartEntity.getSummaryAttr();
        JSONArray penetrateAttr = chartEntity.getPenetrateAttr();
        JSONArray allField = new JSONArray();
        if (CollectionUtils.isNotEmpty(displayAttr)) {
            displayAttr = updateExplain(displayAttr, explainEntityList, single, chartEntity.getCorpid());
            chartEntity.setDisplayAttr(displayAttr);
            allField.addAll(displayAttr);
        }
        if (CollectionUtils.isNotEmpty(rowGroupAttr)) {
            rowGroupAttr = updateExplain(rowGroupAttr, explainEntityList, single, chartEntity.getCorpid());
            chartEntity.setRowGroupAttr(rowGroupAttr);
            allField.addAll(rowGroupAttr);
        }
        if (CollectionUtils.isNotEmpty(colGroupAttr)) {
            colGroupAttr = updateExplain(colGroupAttr, explainEntityList, single, chartEntity.getCorpid());
            chartEntity.setColGroupAttr(colGroupAttr);
            allField.addAll(colGroupAttr);
        }
        if (CollectionUtils.isNotEmpty(chartClassify)) {
            chartClassify = updateExplain(chartClassify, explainEntityList, single, chartEntity.getCorpid());
            chartEntity.setChartClassify(chartClassify);
            allField.addAll(chartClassify);
        }
        if (CollectionUtils.isNotEmpty(chartSeries)) {
            chartSeries = updateExplain(chartSeries, explainEntityList, single, chartEntity.getCorpid());
            chartEntity.setChartSeries(chartSeries);
            allField.addAll(chartSeries);
        }
        if (CollectionUtils.isNotEmpty(summaryAttr)) {
            allField.addAll(summaryAttr);
        }
        if (CollectionUtils.isNotEmpty(penetrateAttr)) {
            allField.addAll(penetrateAttr);
        }
        JSONArray filter = chartEntity.getFilter();
        if (CollectionUtils.isNotEmpty(filter)) {
            allField.addAll(filter);
        }
        //单表时(上面已通过EsUtil.getSingle处理关联数据的情况)，把归属人、统计时间也作为允许筛选的字段以防过滤
        if (Objects.equals(chartEntity.getChartType(), ChartTypeEnum.TARGET_CHART.getCode())
                || Objects.equals(chartEntity.getChartType(), ChartTypeEnum.SECOND_TARGET_CHART.getCode())) {
            JSONObject belongAttr = chartEntity.getBelongAttr();
            JSONObject timeAttr = chartEntity.getTimeAttr();
            if (Objects.nonNull(belongAttr)) {
                allField.add(belongAttr);
            }
            if (Objects.nonNull(timeAttr)) {
                allField.add(timeAttr);
            }
        }
        // 过滤不在chart所有类型字段中的查询条件，自定义pk跳过
        if (!Objects.equals(ChartTypeEnum.PK_CUSTOM.getCode(), chartEntity.getChartType())) {
            existSearchField(allField, searchObjectList);
        }
    }

    @Override
    public ChartSubFormListVO chartGetSubFormList(ChartSubFormListDTO chartSubFormListDTO) throws XbbException {
        ChartSubFormListVO chartSubFormListVO = new ChartSubFormListVO();
        PageHelper pageHelper = new PageHelper(1);
        if (chartSubFormListDTO.getPage() != null && chartSubFormListDTO.getPageSize() != null) {
            pageHelper = new PageHelper(chartSubFormListDTO.getPage(), chartSubFormListDTO.getPageSize());
        }
        chartSubFormListVO.setPageHelper(pageHelper);
        String esId = chartSubFormListDTO.getEsId();
        String corpid = chartSubFormListDTO.getCorpid();
        Long chartId = chartSubFormListDTO.getChartId();
        String subAttr = chartSubFormListDTO.getSubAttr();
        ChartEntity chartEntity = chartCustomModel.getByKey(chartId, corpid);
        JSONArray displayAttr = chartEntity.getDisplayAttr();
        JSONArray penetrateAttr = chartEntity.getPenetrateAttr();
        JSONObject fieldAttr = null;
        for (int i = 0; i < displayAttr.size(); i++) {
            JSONObject obj = displayAttr.getJSONObject(i);
            if (Objects.equals(subAttr, obj.getString("attr"))) {
                fieldAttr = obj;
                break;
            }
        }
        if (fieldAttr == null) {
            for (int i = 0; i < penetrateAttr.size(); i++) {
                JSONObject obj = penetrateAttr.getJSONObject(i);
                if (Objects.equals(subAttr, obj.getString("attr"))) {
                    fieldAttr = obj;
                    break;
                }
            }
        }
        if (fieldAttr == null) {
            return chartSubFormListVO;
        }
        //子表单类型attr
        FieldAttrPojo fieldAttrPojo = JSONObject.parseObject(fieldAttr.toJSONString(), FieldAttrPojo.class);
        SubFormPoJo subFormPoJo = fieldAttrPojo.getSubForm();
        List<? extends FieldAttrEntity> fieldList = subFormPoJo.getItems();
        fieldList.forEach(e -> {
            String attr = e.getAttr();
            if (attr.contains(StringConstant.POINT)) {
                attr = attr.split("\\.")[1];
            }
            e.setAttr(attr);
        });
        //表头字段组装
        List<ChartFieldAttrPojo> headList = JSON.parseArray(JSON.toJSONString(fieldList), ChartFieldAttrPojo.class);
        List<String> includes = new ArrayList<>();
        Map<String, ChartFieldAttrPojo> headAttrMap = new HashMap<>(1 << 4);
        headList.forEach(e -> {
            includes.add(e.getAttr());
            headAttrMap.put(e.getAttr(), e);
        });
        includes.add("id");
        chartSubFormListVO.setHeadList(headList);
        Long dataId = null;
        try {
            dataId = Long.valueOf(esId);
        } catch (NumberFormatException e) {
            //抛异常表示为esId 为多表情况
        }
        List<? extends PaasFormSubDataEntity> entityList;
        IndexTypeEnum indexTypeEnum;
        String subFieldAttr;
        Integer businessType = fieldAttrPojo.getBusinessType();
        if (dataId != null) {
            //单表直接取主表数据源的saasMark跟businessType
            JSONObject driveSource = chartEntity.getDriverSources();
            SlaveSourcePojo sourcePojo = driveSource.toJavaObject(SlaveSourcePojo.class);
            indexTypeEnum = indexTypeModel.getSubIndexType(corpid, sourcePojo.getBusinessType(), sourcePojo.getSaasMark());
            subFieldAttr = fieldAttrPojo.getAttr();
        } else {
            //多表时需要去paas_form中查找表单
            Long formId = chartSubFormListDTO.getFormId();
            Integer saasMark = fieldAttrPojo.getSaasMark();
            if(saasMark == null && businessType != null && !Objects.equals(XbbRefTypeEnum.PAAS.getCode(),businessType) && !Objects.equals(0,businessType) ){
                saasMark = SaasMarkEnum.SAAS.getCode();
            }
            indexTypeEnum = chartResultHelp.getSubFormIndexTypeEnum(saasMark, businessType, formId, corpid);
            if(chartLimitService.getCkFlag()){
                JSONObject formIdDataId = JSONObject.parseObject(esId);
                dataId = formIdDataId.getLong(String.valueOf(formId));
                subFieldAttr = fieldAttrPojo.getOriginalAttr();
            }else {
                //多表非ck时dataId的格式为  公司corpid_表单数据主键id_数仓主键id
                String[] splitData = esId.split(StringConstant.UNDER_LINE);
                try {
                    dataId = Long.valueOf(splitData[1]);
                }catch (Exception e){
                    LOG.error("esId解析失败： " + esId);
                    return chartSubFormListVO;
                }
                subFieldAttr = fieldAttrPojo.getAttr();
            }
        }
        dataId = productModel.getParentDataId(dataId, businessType, corpid);
        //获取子表单数据
        entityList = chartResultHelp.getPaasFormSubDataByIdAndAttr(corpid, dataId, indexTypeEnum, subFieldAttr, pageHelper);
        //获取子表单数据的总条数
        long count = chartResultHelp.getPaasFormSubDataCount(chartSubFormListDTO, dataId, indexTypeEnum, subFieldAttr, pageHelper);
        //attr字段对应结果集映射关系
        Map<String, List<String>> attrToValuesMap = new HashMap<>(1 << 4);
        entityList.forEach(e -> {
            JSONObject dataObj = e.getData();
            dataObj.forEach((attr, value) -> {
                List<String> obj = new ArrayList<>();
                if (value == null) {
                    value = "";
                }
                obj.add(value.toString());
                attrToValuesMap.merge(attr, obj, (v1, v2) -> {
                   v1.addAll(v2);
                   return v1;
                });
            });
        });
        //字段解析
        chartResultHelp.analysisSubFormData(headAttrMap, attrToValuesMap, chartEntity, entityList, chartSubFormListDTO);
        chartSubFormListVO.setResults(entityList);
        chartSubFormListVO.setTotal(count);
        return chartSubFormListVO;
    }

    /**
     * 计算指标总的完成额
     * @param systemCodeEnum 系统指标枚举
     * @param chartResultPojo 参数pojo
     * @return java.lang.Object
     * @throws XbbException
     * @author zcp
     * @date 2019/3/29 15:16
     * @update 支持自定义
     * @since v1.0
     * @version v1.0
     */
    private Object getDepFinish4Total(boolean systemFlag, SystemCodeEnum systemCodeEnum, ChartResultPojo chartResultPojo) throws XbbException {
        String total = "";
        ChartEntity chartEntity = chartResultPojo.getChartEntity();
        //防止在调用首页简报看板底层方法时，使用了其万元开关，或者使用了其数值格式化
        Integer numFormat = chartResultPojo.getNumFormat();
        Boolean numFormatFlag = chartResultPojo.getNumFormatFlag();
        chartResultPojo.setThousandSwitch(false);
        chartResultPojo.setNumFormat(NumFormatEnum.DEFAULT.getCode());
        chartResultPojo.setNumFormatFlag(false);
        if (systemFlag) {
            SystemCodeEnum normalSystemCodeEnum = SystemCodeEnum.formatPerforOrPk2Normal(systemCodeEnum);
            chartResultPojo.setSystemCodeEnum(normalSystemCodeEnum);
            //获取某个人、某个部门的完成总额
            Object finishObject = chartResult.getResult4System(ReturnTypeEnum.VALUE_RETURN, systemCodeEnum.getXbbRefTypeEnum(), chartResultPojo, null);
            total = finishObject.toString();
        } else {
            JSONObject jsonObject = chartEntity.getDriverSources();
            SlaveSourcePojo driverSourcePojo = JSON.toJavaObject(jsonObject, SlaveSourcePojo.class);
            TransmittableThreadLocalUtil.setValue(driverSourcePojo.getSaasMark(), driverSourcePojo.getBusinessType(), driverSourcePojo.getMenuId(), DistributorMarkEnum.OTHER.getCode());
            //获取自定义指标
            total = getCustomResultValue(chartEntity, chartResultPojo);
        }
        //调用简报看板方法处理完后再赋值回去
        chartResultPojo.setNumFormat(numFormat);
        chartResultPojo.setNumFormatFlag(numFormatFlag);
        if ("".equals(total)) {
            total = "0";
        } else {
            String unitTemp = chartEntity.getUnit();
            Double valueDouble = StringUtil.toDouble(total, 0D);
            if (Objects.equals(UnitEnum.NUMBER.getAlias(), unitTemp)) {
                total = StringUtil.formatDouble(valueDouble, 0, 1);
            } else if (Objects.equals(UnitEnum.MONEY.getAlias(), unitTemp)) {
                total = ChartResultUtil.formatValue2Double(false, ValueTypeEnum.VALUE_MONEY, false, valueDouble, NumFormatEnum.DEFAULT, false);
            } else {
                //统一取小数点后两位
                total = StringUtil.formatDouble(valueDouble);
            }
        }
        return total;
    }

    private ChartResultDetailVO gitDiyResult(ChartEntity chartEntity, ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        return gitDiyResult(chartEntity, chartResultPojo,  chartResultDetailVO, false);
    }

    /**
     * 获取自定义
     *
     * @param chartEntity
     * @param chartResultPojo
     * @param chartResultDetailVO
     * @return
     * @throws XbbException
     */
    private ChartResultDetailVO gitDiyResult(ChartEntity chartEntity, ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO,boolean penetrateFlag) throws XbbException {
        //多表的要考虑数据源是否建好
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        SearchRequest searchRequest = new SearchRequest();
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        // 是否是預警腳本跑的
        Boolean isWarningSync = chartResultPojo.getIsWarningSync();
        // 处理不显示离职人员
        chartResultHelp.handleLeaveNoShow(chartEntity);
        customHelp.chartDataEsQuery(chartEntity, sourceBuilder, boolQueryBuilder, searchRequest, chartResultPojo, isWarningSync);
        PageHelper pageHelper = new PageHelper(1);
        if (chartResultPojo.getPage() != null && chartResultPojo.getPageSize() != null) {
            pageHelper = new PageHelper(chartResultPojo.getPage(), chartResultPojo.getPageSize());
        }
        JSONObject result = chartRender(chartEntity, sourceBuilder, boolQueryBuilder, pageHelper, chartResultPojo, searchRequest);
        //自定义图表，只返回图的信息即可
        if (chartEntity.getChartType().equals(ChartTypeEnum.DATA_QUERY_TABLE.getCode())
                || chartEntity.getChartType().equals(ChartTypeEnum.PK_CUSTOM.getCode())
                || chartEntity.getChartType().equals(ChartTypeEnum.DATA_STATISTICS_TABLE.getCode())
                || chartEntity.getChartType().equals(ChartTypeEnum.TARGET_CHART.getCode())
                | chartEntity.getChartType().equals(ChartTypeEnum.SECOND_TARGET_CHART.getCode())) {
            ResultTableVO resultTableVO = new ResultTableVO();
            if (result != null && result.size() > 0) {
                resultTableVO = JSONObject.parseObject(result.toJSONString(), ResultTableVO.class);
            }
            resultTableVO.setPageHelper(pageHelper);
            resultTableVO.setTableName(chartEntity.getName());
            resultTableVO.setChartType(chartEntity.getChartType());
            chartResultDetailVO.setTable(resultTableVO);
            if(Objects.equals(chartEntity.getChartType(), ChartTypeEnum.DATA_QUERY_TABLE.getCode())){
                List<AggsBucketsPojo> aggList = new ArrayList<>();
                ChartResultAggDTO chartResultAggDTO = new ChartResultAggDTO();
                chartResultAggDTO.setIdIn(Arrays.asList(chartEntity.getId()));
                chartResultAggDTO.setLoginUser(chartResultPojo.getLoginUser());
                //非穿透再执行聚合
                if(Objects.equals(chartResultPojo.getPage(),1) && !penetrateFlag){
                    getAggResult(chartResultAggDTO, aggList, chartEntity);
                }
                chartResultDetailVO.setAggList(aggList);
            }
        } else if (chartEntity.getChartType().equals(ChartTypeEnum.BAR_CHART.getCode())
                || chartEntity.getChartType().equals(ChartTypeEnum.LINE_CHART.getCode())
                || chartEntity.getChartType().equals(ChartTypeEnum.AREA_CHART.getCode())
                || chartEntity.getChartType().equals(ChartTypeEnum.RADAR_CHART.getCode())
                || chartEntity.getChartType().equals(ChartTypeEnum.PIE_CHART.getCode())
                || chartEntity.getChartType().equals(ChartTypeEnum.BIAXIAL_CHART.getCode())) {
            ResultChartVO resultChartVO = new ResultChartVO();
            if (result != null && result.size() > 0) {
                resultChartVO = JSONObject.parseObject(result.toJSONString(), ResultChartVO.class);
                resultChartVO.setChartType(chartEntity.getChartType());
            }
            List<ResultChartVO> chartVOList = new ArrayList<>();
            chartVOList.add(resultChartVO);
            chartResultDetailVO.setChart(chartVOList);
        }
        return chartResultDetailVO;
    }

    /**
     * 图表渲染
     *
     * @param chartEntity 图表信息
     * @return JSONObject
     * @author yuqian
     * @date 2019/4/3 10:58
     * @since v1.0
     */
    private JSONObject chartRender(ChartEntity chartEntity, SearchSourceBuilder sourceBuilder, BoolQueryBuilder boolQueryBuilder,
                                   PageHelper pageHelper, ChartResultPojo chartResultPojo, SearchRequest searchRequest) throws XbbException {
        JSONObject result = null;
        //根据图表类型的不同渲染格式也不同
        Integer chartType = chartEntity.getChartType();
        ChartTypeEnum chartTypeEnum = ChartTypeEnum.getByCode(chartType);
        if (chartTypeEnum != null) {
            switch (chartTypeEnum) {
                case DATA_QUERY_TABLE:
                    if (chartEntity.getDisplayAttr() == null || chartEntity.getDisplayAttr().size() == 0) {
                        result = new JSONObject();
                        List list = new ArrayList<>();
                        result.put("customTitle", list);
                        result.put("customData", list);
                        int rowCount = 0;
                        result.put("realRowsCount",rowCount);
                        pageHelper.setRowsCount(rowCount);
                        break;
                    }
                    result = chartsAnalysisByQueryTable(chartEntity, sourceBuilder, boolQueryBuilder, pageHelper, chartResultPojo, searchRequest);
                    break;
                case PK_CUSTOM:// 自定义pk移动端穿透走这里，实在没有办法了
                    if (CollectionsUtil.isEmpty(chartEntity.getDisplayAttr())) {
                        chartEntity.setDisplayAttr(chartEntity.getPenetrateAttr());
                    }
                    Integer businessType = chartEntity.getDriverSources().getInteger(StringConstant.BUSINESS_TYPE);
                    for (Object obj : chartEntity.getDisplayAttr()) {
                        // 放入businessType
                        JSONObject fieldAttrObj = obj instanceof JSONObject ? (JSONObject) obj : null;
                        if (fieldAttrObj == null) {
                            continue;
                        }
                        fieldAttrObj.put(StringConstant.BUSINESS_TYPE, businessType);
                        // 比率字段加百分号
                        if (FieldAttrEntity.isRate(fieldAttrObj.getString("saasAttr"), fieldAttrObj.getString("numberType"))) {
                            fieldAttrObj.put("percentUsed", 1);
                        }
                    }
                    // 走查询表逻辑
                    result = chartsAnalysisByQueryTable(chartEntity, sourceBuilder, boolQueryBuilder, pageHelper, chartResultPojo, searchRequest);
                    break;
                case DATA_STATISTICS_TABLE:
                    //老数据走原来的逻辑
//                    if (CollectionsUtil.isEmpty(chartEntity.getColGroupAttr())) {
//                        result = chartsAnalysisByStatisticsTable(chartEntity, sourceBuilder, boolQueryBuilder, pageHelper, chartResultPojo, searchRequest);
//                    } else {
//                        //存在列表头的逻辑
//                    }
                    result = chartDataByStatisticsTable(chartEntity, sourceBuilder, boolQueryBuilder, pageHelper, chartResultPojo, searchRequest);
                    break;
                case TARGET_CHART:
                case SECOND_TARGET_CHART:
                    if (CollectionUtils.isEmpty(chartEntity.getSummaryAttr())) {
                        result = new JSONObject();
                        List list = new ArrayList<>();
                        result.put("customTitle", list);
                        result.put("customData", list);
                        int rowCount = 0;
                        result.put("realRowsCount",rowCount);
                        pageHelper.setRowsCount(rowCount);
                        break;
                    }
                    result = chartsAnalysisByTarget(chartEntity, sourceBuilder, boolQueryBuilder, pageHelper, chartResultPojo, searchRequest);
                    break;
                case BAR_CHART:
                case LINE_CHART:
                case AREA_CHART:
                case RADAR_CHART:
                case PIE_CHART:
                case BIAXIAL_CHART:
                    result = chartsAnalysisByChart(chartEntity, sourceBuilder, boolQueryBuilder, chartResultPojo, searchRequest);
                    break;
                default:
                    break;
            }
        }

        return result;
    }
    /**
     * 渲染统计表
     *
     * @param tableHead    表头信息
     * @param aggregations es查询结果
     * @param pageTurn     1翻页中
     * @return JSONObject
     * @author yuqian
     * @date 2019/4/11 10:58
     * @since v1.0
     */
    private JSONObject encapsulateStatisticsTable(JSONArray tableHead, Aggregations aggregations, PageHelper pageHelper,
                                                  ChartEntity chartEntity, Map<JSONObject, FieldAttrPojo> parseAttrMap, Map<String, FieldAttrPojo> summaryAttrMap, Integer pageTurn, Boolean exportFlag, BaseDTO baseDTO) {
        JSONObject result = new JSONObject();
        Integer customChartResultSize = 0;
        List<JSONObject> headList = JSONObject.parseArray(tableHead.toJSONString(), JSONObject.class);
        List<LinkedHashMap<String, ChartStatisticsPojo>> chartStatisticsPojoList = new ArrayList<>();
        Map<Integer, List<Map<String, ChartStatisticsPojo>>> pageMap = new LinkedHashMap<>(16);
        Map<Integer, List<Map<String, Object>>> totalMap = new LinkedHashMap<>(16);
        result.put("customTitle", headList);
        Integer rowsCount = 0;
        Integer resultData = 0;
        Integer pageSize = 1;
        Map<String, Object> redisMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (exportFlag != null && exportFlag) {
            //TODO 23884 【成功部】自定义一个访客计划统计图表，按照创建人统计，统计的数量不对少了  验证
            pageHelper.setPageSize(50000);
        } else {
            pageHelper.setPageSize(PageHelper.PAGE_SIZE_HALF);
        }
        if (!BasicConstant.ONE.equals(pageTurn)) {
            if (aggregations != null) {
                recurrenceParseBucket(aggregations, chartStatisticsPojoList, null);
            }

            List<Map<String, Object>> totalList = new ArrayList<>();
            List<Map<String, ChartStatisticsPojo>> pageMapList = new ArrayList<>();
            for (Map<String, ChartStatisticsPojo> map : chartStatisticsPojoList) {
                Map<String, Object> total = new LinkedHashMap<>();
                Iterator<Map.Entry<String, ChartStatisticsPojo>> mapKey = map.entrySet().iterator();
                Map.Entry<String, ChartStatisticsPojo> entry = mapKey.next();
                ChartStatisticsPojo chartStatisticsPojo = map.get(entry.getKey());
                Integer size = 0;
                if (CollectionsUtil.isEmpty(chartStatisticsPojo.getSub())) {
                    ChartStatisticsPojo statisticsPojo;
                    if (map.size() > 1) {
                        while (mapKey.hasNext()) {
                            Map.Entry<String, ChartStatisticsPojo> mapEntry = mapKey.next();
                            String key = mapEntry.getKey();
                            statisticsPojo = map.get(key);
                            total.put(key, Double.valueOf(statisticsPojo.getValue()));
                        }
                    }
                    size = 1;
                } else {
                    size = recurrenceParseMap(total, chartStatisticsPojo.getSub(), customChartResultSize, summaryAttrMap);
                }
                pageMapList.add(map);
                // 对汇总后的数据格式化
                chartResultHelp.formatAggData(summaryAttrMap, total);
                totalList.add(total);
                //当前页面的数据条数
                resultData = resultData + size;
                //总的数据
                rowsCount = rowsCount + size;
                if (resultData >= pageHelper.getPageSize()) {
                    resultData = 0;
                    List<Map<String, ChartStatisticsPojo>> pageList = new ArrayList<>(pageMapList);
                    List<Map<String, Object>> totalTempList = new ArrayList<>(totalList);
                    pageMapList.clear();
                    totalList.clear();
                    Integer index = pageSize++;
                    pageMap.put(index, pageList);
                    totalMap.put(index, totalTempList);
                }
            }
            if (CollectionsUtil.isNotEmpty(pageMapList) || CollectionsUtil.isNotEmpty(totalList)) {
                pageMap.put(pageSize, pageMapList);
                totalMap.put(pageSize, totalList);
            } else {
                if (pageSize != 1) {
                    pageSize--;
                }
            }
            redisMap.put("pageMap", pageMap);
            redisMap.put("totalMap", totalMap);
            redisMap.put("rowsCount", rowsCount);
            redisMap.put("pageSize", pageSize);
            //导出时不更新缓存
            if (exportFlag == null || !exportFlag) {
                paasRedisHelper.setValue(RedisPrefixConstant.INDEX_CUSTOM_STATISTIC_RESULT, chartEntity.getCorpid() + "_" + chartEntity.getId(), redisMap, TimeConstant.TINY_DURATION);
            }
        } else {
            String redisResult = paasRedisHelper.getValue(RedisPrefixConstant.INDEX_CUSTOM_STATISTIC_RESULT, chartEntity.getCorpid() + "_" + chartEntity.getId());
            if (StringUtil.isNotEmpty(redisResult)) {
                redisMap = JSONObject.parseObject(redisResult, Feature.OrderedField);
                pageMap = JSON.parseObject(redisMap.get("pageMap").toString(), new TypeReference<Map<Integer, List<Map<String, ChartStatisticsPojo>>>>() {
                }, Feature.OrderedField);
                totalMap = JSON.parseObject(redisMap.get("totalMap").toString(), new TypeReference<Map<Integer, List<Map<String, Object>>>>() {
                }, Feature.OrderedField);
                rowsCount = (Integer) redisMap.get("rowsCount");
                pageSize = (Integer) redisMap.get("pageSize");
            } else {
                encapsulateStatisticsTable(tableHead, aggregations, pageHelper, chartEntity, parseAttrMap, summaryAttrMap, 0, exportFlag, baseDTO);
            }
        }
        List<Map<String, ChartStatisticsPojo>> resultPage = pageMap.get(pageHelper.getCurrentPageNum());
        parseAttrMap(resultPage, parseAttrMap, summaryAttrMap, chartEntity, baseDTO);
        if (resultPage == null) {
            resultPage = new ArrayList<>();
        }
        result.put("customData", resultPage);
        List<Map<String, Object>> decimalMap = totalMap.get(pageHelper.getCurrentPageNum());
        if (decimalMap != null) {
            for (Map<String, Object> map : decimalMap) {
                Iterator<Map.Entry<String, Object>> it = map.entrySet().iterator();
                while (it.hasNext()) {
                    Map.Entry<String, Object> entry = it.next();
                    String key = entry.getKey();
                    String value = String.valueOf(entry.getValue());
                    if (!key.contains("count")) {
                        map.put(key, value);
                    }
                }
            }
        }
        result.put("customTotal", totalMap.get(pageHelper.getCurrentPageNum()));
        pageHelper.setRowsCount(rowsCount);
        result.put("realRowsCount", rowsCount);
        if (rowsCount > ChartConstant.MAX_SIZE) {
            pageHelper.setRowsCount(ChartConstant.MAX_SIZE);
        }
        pageHelper.setPageTotal(pageSize);
        return result;
    }

    /**
     * 渲染指标图
     * @param tableHead    表头信息
     * @param aggregations es查询结果
     * @param pageTurn     1翻页中
     * @return JSONObject
     * @author weiming
     * @date 2020/9/27 08:52
     * @since v1.0
     */
    private JSONObject encapsulateTargetChart(JSONArray tableHead, Aggregations aggregations, PageHelper pageHelper,
                                                  ChartEntity chartEntity, Map<JSONObject, FieldAttrPojo> parseAttrMap, Map<String, FieldAttrPojo> summaryAttrMap, Integer pageTurn, Boolean exportFlag, BaseDTO baseDTO,List<String> secondTargetKey) throws XbbException {
        JSONObject result = new JSONObject();
        Integer customChartResultSize = 0;
        List<JSONObject> headList = JSONObject.parseArray(tableHead.toJSONString(), JSONObject.class);
        List<FieldAttrPojo> fieldAttrPojoList = JSON.parseArray(chartEntity.getSummaryAttr().toJSONString(), FieldAttrPojo.class);
        List<FieldAttrPojo> rowFieldAttrPojoList = JSONArray.parseArray(chartEntity.getRowGroupAttr().toJSONString(), FieldAttrPojo.class);
        FieldAttrPojo rowGroupAttr = new FieldAttrPojo();
        if (CollectionsUtil.isNotEmpty(rowFieldAttrPojoList)) {
            rowGroupAttr = rowFieldAttrPojoList.get(0);
        }
        FieldAttrPojo fieldAttrPojo = fieldAttrPojoList.get(0);
        JSONArray advancedComputing = fieldAttrPojo.getAdvancedComputing();
        String sumKey = fieldAttrPojo.getAttr() + "&" + fieldAttrPojo.getFieldType();
        Integer chartType = chartEntity.getChartType();
        // 同环比过渡用map
        Map<String, Object> interimMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        // 是否同环比
        boolean isYearChain = chartResultHelp.isYearChain4Date(rowGroupAttr, advancedComputing);
        List<LinkedHashMap<String, ChartStatisticsPojo>> chartStatisticsPojoList = new ArrayList<>();
        Map<Integer, List<Map<String, ChartStatisticsPojo>>> pageMap = new LinkedHashMap<>(16);
        Map<Integer, List<Map<String, Object>>> totalMap = new LinkedHashMap<>(16);
        result.put("customTitle", headList);
        Integer rowsCount = 0;
        Integer resultData = 0;
        Integer pageSize = 1;
        String totalSum = "";
        Map<String, Object> redisMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (!BasicConstant.ONE.equals(pageTurn)) {
            if (aggregations != null) {
                FieldAttrPojo summaryAttrPojo = chartEntity.getSummaryAttr().getJSONObject(0).toJavaObject(FieldAttrPojo.class);
                if (CollectionUtils.isNotEmpty(chartEntity.getRowGroupAttr())) {
                    totalSum = parseTargetBucket(aggregations, summaryAttrPojo, chartStatisticsPojoList,0);
                }else{
                    totalSum = parseTargetBucket(aggregations, summaryAttrPojo, chartStatisticsPojoList, 1);
                }
            }
            List<Map<String, Object>> totalList = new ArrayList<>();
            List<Map<String, ChartStatisticsPojo>> pageMapList = new ArrayList<>();
            for (int i = 0; i < chartStatisticsPojoList.size(); i++) {
                Map<String, ChartStatisticsPojo> map = chartStatisticsPojoList.get(i);
                interimMap.clear();
                Map<String, Object> total = new LinkedHashMap<>();
                Iterator<Map.Entry<String, ChartStatisticsPojo>> mapKey = map.entrySet().iterator();
                Map.Entry<String, ChartStatisticsPojo> entry = mapKey.next();
                ChartStatisticsPojo chartStatisticsPojo = map.get(entry.getKey());
                Integer size = 0;
                if (CollectionsUtil.isEmpty(chartStatisticsPojo.getSub())) {
                    ChartStatisticsPojo statisticsPojo;
                    if (map.size() > 1) {
                        while (mapKey.hasNext()) {
                            Map.Entry<String, ChartStatisticsPojo> mapEntry = mapKey.next();
                            String key = mapEntry.getKey();
                            statisticsPojo = map.get(key);
                            total.put(key, Double.valueOf(statisticsPojo.getValue()));
                            interimMap.put(key, statisticsPojo.getOriginValue());
                        }
                    }
                    size = 1;
                } else {
                    size = recurrenceParseMap(total, chartStatisticsPojo.getSub(), customChartResultSize, summaryAttrMap);
                }
                // 同环比
                if (isYearChain) {
                    String oldVal = getOldValue4Target(rowGroupAttr, advancedComputing, sumKey, chartType, chartStatisticsPojoList, i, chartStatisticsPojo);
                    String yearChainValue = chartResultHelp.getYearChainValue(fieldAttrPojo, oldVal, interimMap.get(sumKey).toString());
                    map.get(sumKey).setValue(yearChainValue);
                }
                pageMapList.add(map);
                // 对汇总后的数据格式化
                chartResultHelp.formatAggData(summaryAttrMap, total);
                totalList.add(total);
                //当前页面的数据条数
                resultData = resultData + size;
                //总的数据
                rowsCount = rowsCount + size;
                if (resultData >= pageHelper.getPageSize()) {
                    resultData = 0;
                    List<Map<String, ChartStatisticsPojo>> pageList = new ArrayList<>(pageMapList);
                    List<Map<String, Object>> totalTempList = new ArrayList<>(totalList);
                    pageMapList.clear();
                    totalList.clear();
                    Integer index = pageSize++;
                    pageMap.put(index, pageList);
                    totalMap.put(index, totalTempList);
                }
            }
            if (CollectionsUtil.isNotEmpty(pageMapList) || CollectionsUtil.isNotEmpty(totalList)) {
                pageMap.put(pageSize, pageMapList);
                totalMap.put(pageSize, totalList);
            } else {
                if (pageSize != 1) {
                    pageSize--;
                }
            }
            redisMap.put("pageMap", pageMap);
            redisMap.put("totalMap", totalMap);
            redisMap.put("rowsCount", rowsCount);
            redisMap.put("pageSize", pageSize);
            redisMap.put("totalSum",totalSum);
            //导出时不更新缓存
            if (exportFlag == null || !exportFlag) {
                paasRedisHelper.setValue(RedisPrefixConstant.INDEX_CUSTOM_STATISTIC_RESULT, chartEntity.getCorpid() + "_" + chartEntity.getId(), redisMap, TimeConstant.TINY_DURATION);
            }
        } else {
            String redisResult = paasRedisHelper.getValue(RedisPrefixConstant.INDEX_CUSTOM_STATISTIC_RESULT, chartEntity.getCorpid() + "_" + chartEntity.getId());
            if (StringUtil.isNotEmpty(redisResult)) {
                redisMap = JSONObject.parseObject(redisResult, Feature.OrderedField);
                pageMap = JSON.parseObject(redisMap.get("pageMap").toString(), new TypeReference<Map<Integer, List<Map<String, ChartStatisticsPojo>>>>() {
                }, Feature.OrderedField);
                totalMap = JSON.parseObject(redisMap.get("totalMap").toString(), new TypeReference<Map<Integer, List<Map<String, Object>>>>() {
                }, Feature.OrderedField);
                rowsCount = (Integer) redisMap.get("rowsCount");
                pageSize = (Integer) redisMap.get("pageSize");
                totalSum = String.valueOf(redisMap.get("totalSum"));
            } else {
                encapsulateTargetChart(tableHead, aggregations, pageHelper, chartEntity, parseAttrMap, summaryAttrMap, 0, exportFlag, baseDTO,secondTargetKey);
            }
        }
        if ("".equals(totalSum)){
            LOG.error(BiErrorCodeEnum.API_ERROR_241019.getMsg());
            throw new XbbException(BiErrorCodeEnum.API_ERROR_241019);
        }
        List<Map<String, ChartStatisticsPojo>> resultPage = pageMap.get(pageHelper.getCurrentPageNum());
        parseAttrMap(resultPage, parseAttrMap, summaryAttrMap, chartEntity, baseDTO);
        if (resultPage == null) {
            resultPage = new ArrayList<>();
        }
        result.put("customData", resultPage);
        List<Map<String, Object>> decimalMap = totalMap.get(pageHelper.getCurrentPageNum());
        if (decimalMap != null) {
            for (Map<String, Object> map : decimalMap) {
                Iterator<Map.Entry<String, Object>> it = map.entrySet().iterator();
                while (it.hasNext()) {
                    Map.Entry<String, Object> entry = it.next();
                    String key = entry.getKey();
                    String value = String.valueOf(entry.getValue());
                    if (!key.contains("count")) {
                        map.put(key, value);
                    }
                }
            }
        }
        List<Map<String, Object>> curTotalList = totalMap.get(pageHelper.getCurrentPageNum());
        curTotalList = curTotalList == null ? new ArrayList<>():curTotalList;
        pageHelper.setRowsCount(rowsCount);
        result.put("realRowsCount", rowsCount);
        result.put("totalSum",totalSum);
        packageSecondValue(chartEntity,secondTargetKey,rowFieldAttrPojoList,resultPage,curTotalList,sumKey,summaryAttrMap,result,fieldAttrPojo);
        result.put("customTotal", curTotalList);
        if (rowsCount > ChartConstant.MAX_SIZE) {
            pageHelper.setRowsCount(ChartConstant.MAX_SIZE);
        }
        pageHelper.setPageTotal(pageSize);
        // 指标图数据预警start
        Map<String,Object> dwVOMap = chartResultHelp.getDWQueryListVO(baseDTO,chartEntity);
        DataWarningQueryListVO dataWarningQueryListVO = null;
        String key = "";
        if (Objects.nonNull(dwVOMap)){
            dataWarningQueryListVO = (DataWarningQueryListVO) dwVOMap.get("dataWarningQueryListVO");
            key = (String)dwVOMap.get("key");
        }
        String rowAttr = "";
        if (null != chartEntity && CollectionUtils.isNotEmpty(chartEntity.getRowGroupAttr())){
            FieldAttrPojo fieldAttrPojo2 = chartEntity.getRowGroupAttr().getJSONObject(0).toJavaObject(FieldAttrPojo.class);
            rowAttr = fieldAttrPojo2.getAttr() + "&" +fieldAttrPojo2.getFieldType();
        }
        // 为了防止一个当前预警数据同时触发多个预警设置，不知道选那个，取这个预警数据到预警设置最接近的数据
        Map<String,Object> distinctMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<WarningValuePojo> warningValues = new ArrayList<>();
        // 预警的接口
        int warningIndex = 0;
        if (Objects.nonNull(dataWarningQueryListVO) && CollectionUtils.isNotEmpty(dataWarningQueryListVO.getDataWarningQueryVOList()) && Objects.nonNull(pageMap) && pageMap.size()>0){
            for (DataWarningQueryVO item : dataWarningQueryListVO.getDataWarningQueryVOList()) {
                int valueIndex = 0;
                for (Map<String, ChartStatisticsPojo> stringObjectMap : pageMap.get(pageHelper.getCurrentPageNum())) {
                    if (chartResultHelp.checkIsTrigger(item.getTriggerCondition(), String.valueOf(stringObjectMap.get(key).getValue()))) {
                        WarningValuePojo pojo = new WarningValuePojo();
                        pojo.setRowValue(String.valueOf(stringObjectMap.get(rowAttr).getValue()));
                        pojo.setWarningFlag(true);
                        pojo.setValue(String.valueOf(stringObjectMap.get(key).getValue()));
                        pojo.setColor(item.getColor());
                        if (chartResultHelp.isCover(item.getTriggerCondition(), String.valueOf(stringObjectMap.get(key).getValue()),distinctMap,valueIndex)){
                            if ((warningValues.size()-1) >= valueIndex){
                                warningValues.set(valueIndex,pojo);
                            }else {
                                warningValues.add(pojo);
                            }
                        }else if (warningValues.size() < pageMap.get(pageHelper.getCurrentPageNum()).size()){
                            warningValues.add(pojo);
                        }
                    }else if (warningIndex == 0){
                        WarningValuePojo pojo = new WarningValuePojo();
                        pojo.setRowValue(String.valueOf(stringObjectMap.get(rowAttr).getValue()));
                        pojo.setWarningFlag(false);
                        pojo.setValue(String.valueOf(stringObjectMap.get(key).getValue()));
                        warningValues.add(pojo);
                    }
                    valueIndex ++;
                }
                warningIndex ++;
            }
        }else if (Objects.nonNull(dataWarningQueryListVO) && StringUtil.isNotEmpty(totalSum)){
            for (DataWarningQueryVO item : dataWarningQueryListVO.getDataWarningQueryVOList()) {
                int valueIndex = 0;
                if (chartResultHelp.checkIsTrigger(item.getTriggerCondition(), totalSum)) {
                    WarningValuePojo pojo = new WarningValuePojo();
                    pojo.setWarningFlag(true);
                    pojo.setValue(totalSum);
                    pojo.setColor(item.getColor());
                    if (chartResultHelp.isCover(item.getTriggerCondition(), totalSum,distinctMap,valueIndex)){
                        if ((warningValues.size()-1) >= valueIndex){
                            warningValues.set(valueIndex,pojo);
                        }else {
                            warningValues.add(pojo);
                        }
                    }else if (warningValues.size() < 1){
                        warningValues.add(pojo);
                    }
                }else if (warningIndex == 0){
                    WarningValuePojo pojo = new WarningValuePojo();
                    pojo.setWarningFlag(false);
                    pojo.setValue(totalSum);
                    warningValues.add(pojo);
                }
                warningIndex ++;
            }
        }
        result.put("warningValues",warningValues);
        // 指标图数据预警end
        return result;
    }

    /**
     * 封装副指标图
     * @param chartEntity
     * @param secondTargetKey
     * @param rowFieldAttrPojoList
     * @param resultPage
     * @param curTotalList
     * @param sumKey
     * @param summaryAttrMap
     * @param result
     * @throws XbbException
     */
    void packageSecondValue(ChartEntity chartEntity,List<String> secondTargetKey,List<FieldAttrPojo> rowFieldAttrPojoList,List<Map<String, ChartStatisticsPojo>> resultPage,
                            List<Map<String, Object>> curTotalList,String sumKey,Map<String, FieldAttrPojo> summaryAttrMap,JSONObject result,FieldAttrPojo summaryAttrPojo) throws XbbException {
        // 是主副指标，且高级计算不为无
        if (Objects.equals(chartEntity.getChartType(),ChartTypeEnum.SECOND_TARGET_CHART.getCode()) && CollectionUtils.isNotEmpty(secondTargetKey) && secondTargetKey.size()>1){
            if (CollectionUtils.isNotEmpty(rowFieldAttrPojoList)){
                // 中英文，获取要拼接的前缀和后缀
                Boolean englishFlag = Objects.equals(LocaleContextHolder.getLocale().getLanguage(), I18nStringConstant.ENGLISH_LANGUAGE);
                List<FieldAttrPojo> secondTargetList;
                if(CollectionUtils.isNotEmpty(chartEntity.getSecondTargetAttr())){
                    secondTargetList = JSONArray.parseArray(chartEntity.getSecondTargetAttr().toJSONString(), FieldAttrPojo.class);
                }else {
                    throw new XbbException(ChartErrorCodeEnum.API_ERROR_310001);
                }
                FieldAttrPojo fieldAttrPojo = secondTargetList.get(0);
                JSONArray advancedComputing = fieldAttrPojo.getAdvancedComputing();
                String timeDimension = secondTargetList.get(0).getTimeDimension();
                TimeDimensionEnum timeDimensionEnum = TimeDimensionEnum.getByFormatStr(timeDimension);
                String ratePrefix = I18nMessageUtil.getMessage(I18nStringConstant.LAST) + timeDimensionEnum.getName();
                String rateSuffix = I18nMessageUtil.getMessage(I18nStringConstant.YEAR_ON_YEAR);
                if (englishFlag){
                    ratePrefix = I18nMessageUtil.getMessage(I18nStringConstant.LAST) + " " + timeDimensionEnum.getName() + " ";
                }

                // 获取之前和现在的两个值
                String rowKey = rowFieldAttrPojoList.get(0).getAttr() + "&" + rowFieldAttrPojoList.get(0).getFieldType();
                int index = 0;
                List<Map<String, Object>> secondCustomTotal = new ArrayList<>();
                List<Map<String, Object>> curTotalListTemp = (List<Map<String, Object>>)CloneUtil.deepClone(curTotalList);;
                Iterator<Map<String, ChartStatisticsPojo>> iterator = resultPage.iterator();
                String curValue = "0";
                String lastValue = "0";
                while(iterator.hasNext()){
                    Map<String, ChartStatisticsPojo> item = iterator.next();
                    ChartStatisticsPojo rowPojo = item.get(rowKey);
                    if (Objects.nonNull(rowPojo) && Objects.equals(rowPojo.getOriginValue(), secondTargetKey.get(0))) {
                        if (index <= curTotalList.size()){
                            secondCustomTotal.add(curTotalList.get(index));
                            lastValue = String.valueOf(curTotalList.get(index).get(sumKey));
                            curTotalListTemp.remove(index);
                        }
                    }else if (Objects.nonNull(rowPojo) && Objects.equals(rowPojo.getOriginValue(), secondTargetKey.get(1))){
                        curValue = String.valueOf(curTotalList.get(index).get(sumKey));
                    }
                    index ++;
                }
                curTotalList = curTotalListTemp;
                // 赋默认值0
                if (CollectionUtils.isEmpty(curTotalList)){
                    Map<String,Object> curTotalMap = new HashMap<String,Object>(){{put(sumKey,0);}};
                    chartResultHelp.formatAggData(summaryAttrMap, curTotalMap);
                    curTotalList.add(curTotalMap);
                }
                if (CollectionUtils.isEmpty(secondCustomTotal)){
                    Map<String,Object> secondTotalMap = new HashMap<String,Object>(){{put(sumKey,0);}};
                    chartResultHelp.formatAggData(summaryAttrMap, secondTotalMap);
                    secondCustomTotal.add(secondTotalMap);
                }
                curTotalList.addAll(secondCustomTotal);
                String rate;
                curValue = chartResultHelp.reverseFieldAttrPojoFormat(summaryAttrPojo,curValue);
                lastValue = chartResultHelp.reverseFieldAttrPojoFormat(summaryAttrPojo,lastValue);
                Float curFloatValue = Float.parseFloat(curValue);
                Float lastFloatValue = Float.parseFloat(lastValue);
                // 增长、下降或者持平
                if (curFloatValue.compareTo(lastFloatValue) == 0){
                    result.put(StringConstant.RATE_TYPE, RateTypeEnum.INVARIANT.getCode());
                }else if (curFloatValue.compareTo(lastFloatValue) > 0){
                    result.put(StringConstant.RATE_TYPE, RateTypeEnum.INCREASE.getCode());
                }else {
                    result.put(StringConstant.RATE_TYPE, RateTypeEnum.DECREASE.getCode());
                }
                // 求rate值
                boolean isYearChain = chartResultHelp.isYearChain4Subtitle(advancedComputing);
                if (isYearChain){
                    String advancedComputingSecond = advancedComputing.getString(1);
                    AdvancedComputingSecondEnum advancedComputingSecondEnum = AdvancedComputingSecondEnum.getByAlias(advancedComputingSecond);
                    Float diffFloat = curFloatValue - lastFloatValue;
                    switch (advancedComputingSecondEnum){
                        case YEAR_VALUE:
                        case CHAIN_VALUE:
                            rate = String.valueOf(Math.abs(diffFloat.floatValue()));
                            break;
                        case YEAR_RATE:
                        case CHAIN_RATE:
                            if (lastFloatValue.compareTo(0.0f) == 0){
                                if (diffFloat.compareTo(0.0f) == 0){
                                    rate = "0";
                                }else{
                                    rate = "1";
                                }
                            }else {
                                rate = String.valueOf(Math.abs(diffFloat/lastFloatValue));
                            }
                            break;
                        default:
                            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
                    }
                    // 是否环比
                    boolean isChain = Objects.equals(AdvancedComputingSecondEnum.getYearOrChain(advancedComputing.getString(1)),2);
                    if (isChain){
                        rateSuffix = I18nMessageUtil.getMessage(I18nStringConstant.SEQUENTIAL);
                    }
                }else {
                    // 默认环比增长值
                    rate = String.valueOf(Math.abs(curFloatValue-lastFloatValue));
                }
                curValue = chartResultHelp.fieldAttrPojoFormat(summaryAttrPojo,curValue);
                lastValue = chartResultHelp.fieldAttrPojoFormat(summaryAttrPojo,lastValue);
                rate = chartResultHelp.fieldAttrPojoFormat(fieldAttrPojo,rate);
                result.put("rateTitle",ratePrefix + rateSuffix);
                result.put("totalSum",curValue);
                result.put("secondTotalSum",lastValue);
                result.put("rate", rate);
            }
        }
    }
    /**
     * 渲染图表信息
     *
     * @param chartEntity  图表信息
     * @param tableHead    表头
     * @param aggregations 聚合详情
     * @return JSONObject
     * @author zhouwq
     * @date 2019/4/12 14:10
     */
    private JSONObject chartStatistics(ChartEntity chartEntity, JSONArray tableHead, Aggregations aggregations, BaseDTO baseDTO) throws XbbException {
        JSONObject result = new JSONObject();
        List<JSONObject> headList = JSONObject.parseArray(tableHead.toJSONString(), JSONObject.class);
        List<LinkedHashMap<String, ChartStatisticsPojo>> chartStatisticsPojoList = new ArrayList<>();
        result.put("customTitle", headList);
        if (aggregations != null) {
            recurrenceParseBucket(aggregations, chartStatisticsPojoList);
        }
        List<String> xAxis = new ArrayList<>();
        List<String> xAxisKeys = new ArrayList<>();
        List<String> legend = new ArrayList<>();
        List<String> legendKeys = new ArrayList<>();
        Map<String, JSONObject> jsonArrayMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        addJsonArray(chartStatisticsPojoList, xAxis, legend, jsonArrayMap, result, chartEntity, xAxisKeys, legendKeys, baseDTO);

        List<ResultDataChartVO> data = new ArrayList<>(xAxis.size());
        List<ResultDataSeriesChartVO> dataSeries = new ArrayList<>(xAxis.size());
        JSONArray chartValue = new JSONArray(chartEntity.getChartValue());
        JSONArray chartValueSecond = chartEntity.getChartValueSecond();
        JSONArray chartValueList = new JSONArray(){{addAll(chartValue);}};
        if (CollectionUtils.isNotEmpty(chartEntity.getChartValueSecond())){
            chartValueList.addAll(chartValueSecond);
        }
        List<FieldAttrPojo> fieldAttrPojoList = JsonHelperUtil.parseArray(chartValueList.toJSONString(), FieldAttrPojo.class);
        FieldAttrPojo fieldAttrPojo = JsonHelperUtil.parseArray(chartEntity.getChartValue().toJSONString(), FieldAttrPojo.class).get(0);
        // 如果是折线图或者柱形图查询出开启的预警查询每个预警最近的3条预警历史
        Map<String,Object> dwVOMap = chartResultHelp.getDWQueryListVO(baseDTO,chartEntity);
        DataWarningQueryListVO dataWarningQueryListVO = null;
        if (null != dwVOMap){
            dataWarningQueryListVO = (DataWarningQueryListVO) dwVOMap.get("dataWarningQueryListVO");
        }
        if (chartEntity.getChartType().equals(ChartTypeEnum.PIE_CHART.getCode())) {
            chartDataSeriesRender(xAxis, legend, jsonArrayMap, result, dataSeries, fieldAttrPojo);
        } else {
            chartDataRender(chartEntity,xAxisKeys,xAxis, legendKeys, legend,jsonArrayMap, result, data, chartEntity.getBiaxial(),fieldAttrPojoList,chartEntity.getChartValue().size(),dataWarningQueryListVO);
        }
        return result;
    }

    /**
     * jsonArray结果集 组装
     *
     * @param chartStatisticsPojoList 聚合结果集
     * @param xAxis                   X轴-分类
     * @param legend                  系列
     * @param jsonArrayMap            结果集
     * @param result                  最终返回result集合
     * @param chartEntity             图表实体
     * @param xAxisKeys               x轴分类key存储
     * @param legendKeys              y轴系列key存储
     * @author zhouwq
     * @date 2019/4/12 10:21
     */
    private void addJsonArray(List<LinkedHashMap<String, ChartStatisticsPojo>> chartStatisticsPojoList, List<String> xAxis, List<String> legend, Map<String, JSONObject> jsonArrayMap, JSONObject result,
                              ChartEntity chartEntity, List<String> xAxisKeys, List<String> legendKeys, BaseDTO baseDTO) throws XbbException {
        JSONObject xAxisObject = chartEntity.getChartClassify().getJSONObject(0);
        FieldAttrPojo xAxisAttr = JSONObject.parseObject(xAxisObject.toJSONString(), FieldAttrPojo.class);
        JSONArray chartSeriesArray = chartEntity.getChartSeries();
        JSONObject legendObject = new JSONObject();
        if (chartSeriesArray != null && chartSeriesArray.size() > 0) {
            legendObject = chartEntity.getChartSeries().getJSONObject(0);
        }
        FieldAttrPojo legendAttr = JSONObject.parseObject(legendObject.toJSONString(), FieldAttrPojo.class);
        String corpId = chartEntity.getCorpid();
        JSONArray chartValue = new JSONArray(chartEntity.getChartValue());
        JSONArray chartValueSecond = chartEntity.getChartValueSecond();
        JSONArray chartValueList = new JSONArray(){{addAll(chartValue);}};
        JSONArray jsonArray = new JSONArray();
        // 计算字段，日期公式时标题legend回显需要
        Map<String,String> computedDateDiffMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (Map<String, ChartStatisticsPojo> chart : chartStatisticsPojoList) {
            ChartStatisticsPojo chartStatistics = chart.get(ChartAggNameEnum.AGG_FIRST.getStr());
            xAxisKeys.add(chartStatistics.getValue());
            //单表情况下负责人类型处理
//            if (EsHelper.isTeamLogicByFieldType(xAxisAttr.getFieldType(), xAxisAttr.getBusinessType()) && chartEntity.getSingle().equals(BasicConstant.ONE)) {
//                Map<String, ChartStatisticsPojo> subMap = new HashMap<>(1);
//                subMap.put(ChartAggNameEnum.SUM_TOTAL.getStr(), chart.get("count"));
//                chartStatistics.setSub(Collections.singletonList(subMap));
//            }
            List<LinkedHashMap<String, ChartStatisticsPojo>> legendList = chartStatistics.getSub();
            if (legendList != null && legendList.size() > 0) {
                Collections.sort(legendList, (o1, o2) -> {
                    Set<String> p1Set = o1.keySet();
                    Set<String> p2Set = o2.keySet();
                    String p1Key;
                    String p2Key;
                    if (Objects.isNull(p1Set) || Objects.isNull(p2Set)){
                        return 1;
                    } else {
                        p1Key = new ArrayList<>(p1Set).get(0);
                        p2Key = new ArrayList<>(p2Set).get(0);
                        int p1EndIndex = 0;
                        int p2EndIndex = 0;
                        if (((p1EndIndex = p1Key.lastIndexOf("&")) != -1) && ((p2EndIndex = p2Key.lastIndexOf("&")) != -1)){
                            String p1Sort = p1Key.substring(p1EndIndex+1);
                            String p2Sort = p2Key.substring(p2EndIndex+1);
                            return p1Sort.compareTo(p2Sort);
                        }
                        return 1;
                    }
                });
                for (Map<String, ChartStatisticsPojo> chartLegend : legendList) {
                    //存在agg2，则为三层聚合
                    if (chartLegend.containsKey(ChartAggNameEnum.AGG_SECOND.getStr())) {
                        JSONObject agg2Object = new JSONObject();
                        ChartStatisticsPojo chartAgg2 = chartLegend.get(ChartAggNameEnum.AGG_SECOND.getStr());
                        String legendValue = chartAgg2.getValue();
                        if (!legendKeys.contains(legendValue)) {
                            legendKeys.add(legendValue);
                        }
                        //单表情况下负责人类型处理
//                        if (EsHelper.isTeamLogicByFieldType(legendAttr.getFieldType(), legendAttr.getBusinessType()) && chartEntity.getSingle().equals(BasicConstant.ONE)) {
//                            Map<String, ChartStatisticsPojo> subMap = new HashMap<>(1);
//                            subMap.put(ChartAggNameEnum.SUM_TOTAL.getStr(), chartLegend.get("count"));
//                            chartStatistics.setSub(Collections.singletonList(subMap));
//                        }
                        List<LinkedHashMap<String, ChartStatisticsPojo>> subList = chartAgg2.getSub();
                        if (CollectionUtils.isEmpty(subList)){
                            continue;
                        }
                        for (LinkedHashMap<String, ChartStatisticsPojo> sub : subList) {
                            ChartStatisticsPojo chartPojo;
                            if (sub.containsKey(ChartAggNameEnum.SUM_TOTAL.getStr())) {
                                chartPojo = sub.get(ChartAggNameEnum.SUM_TOTAL.getStr());
                                agg2Object.put(ChartAggResultEnum.COUNT.getStr(), chartPojo.getValue());
                            }
                            Long docCounts = chartAgg2.getDocCount();
                            agg2Object.put(ChartAggResultEnum.X_AXIS.getStr(), chartStatistics.getValue());
                            agg2Object.put(ChartAggResultEnum.LEGEND.getStr(), legendValue);
                            agg2Object.put(ChartAggResultEnum.DOC_COUNT.getStr(), docCounts);
                            jsonArray.add(agg2Object);
                        }
                    } else {
                        // 两层聚合情况
                        for (Map.Entry<String, ChartStatisticsPojo> entry : chartLegend.entrySet()) {
                            String k = entry.getKey();
                            if (!k.contains(ChartAggNameEnum.SUM_TOTAL.getStr())) {
                                continue;
                            }
                            //2层聚合情况下chartValue值(字段名)作为系列
                            ChartStatisticsPojo chartPojo = entry.getValue();
                            //chartValue值(字段名)
                            String attrSum = "";
                            String suffix = "";
                            for (Object item : chartValueList) {
                                JSONObject jsonObject = (JSONObject) item;
                                if (k.contains(ChartAggNameEnum.SUM_TOTAL.getStr() + "&" + jsonObject.getLong("formId") + "&" + jsonObject.getString("attr") + "&" + PaasConstant.LEFT)) {
                                    attrSum = jsonObject.getString("labelName") + "&" + PaasConstant.LEFT;
                                    suffix = getSuffix(jsonObject);
                                    break;
                                }
                            }
                            if (CollectionUtils.isNotEmpty(chartValueSecond)) {
                                for (Object item : chartValueSecond) {
                                    JSONObject jsonObject = (JSONObject) item;
                                    if (k.contains(ChartAggNameEnum.SUM_TOTAL.getStr() + "&" + jsonObject.getLong("formId") + "&" + jsonObject.getString("attr") + "&" + PaasConstant.RIGHT)) {
                                        attrSum = jsonObject.getString("labelName") + "&" + PaasConstant.RIGHT;
                                        suffix = getSuffix(jsonObject);
                                        break;
                                    }
                                }
                            }
                            if (StringUtil.isEmpty(attrSum)) {
                                continue;
                            }
                            if (!legendKeys.contains(attrSum)) {
                                legendKeys.add(attrSum);
                                if (StringUtil.isNotEmpty(suffix)){
                                    computedDateDiffMap.put(attrSum,suffix);
                                }
                            }
                            JSONObject aggObject = new JSONObject();
                            Long docCounts = chartStatistics.getDocCount();
                            aggObject.put(ChartAggResultEnum.X_AXIS.getStr(), chartStatistics.getValue());
                            aggObject.put(ChartAggResultEnum.LEGEND.getStr(), attrSum);
                            aggObject.put(ChartAggResultEnum.COUNT.getStr(), chartPojo.getValue());
                            aggObject.put(ChartAggResultEnum.DOC_COUNT.getStr(), docCounts);
                            jsonArray.add(aggObject);
                        }
                    }
                }
            }
        }

        Map<String, String> xAxisValueMap = valueListAnalysis(xAxisAttr, corpId, xAxisKeys, chartEntity, baseDTO);
        xAxisKeys.forEach(str -> {
            String xAxisResult = Objects.equals(null, xAxisValueMap.get(str)) ? "" : xAxisValueMap.get(str);
            xAxis.add(xAxisResult);
        });
        Map<String, String> legendValueMap = valueListAnalysis(legendAttr, corpId, legendKeys, chartEntity, baseDTO);
        List<String> legendTempKeys = new ArrayList<>();
        legendKeys.forEach(str -> {
            String legendResult = Objects.equals(null, legendValueMap.get(str)) ? "" : legendValueMap.get(str);
            int endIndex = 0;
            String suffix = null != computedDateDiffMap.get(str) ? computedDateDiffMap.get(str) : "";
            if (((endIndex = legendResult.lastIndexOf("&")) != -1) && ((endIndex = legendResult.lastIndexOf("&",endIndex)) != -1)){
                legendTempKeys.add(str.substring(0,endIndex) + suffix);
                legendResult = legendResult.substring(0,endIndex) + suffix;
            }
            legend.add(legendResult);
        });
        if (CollectionUtils.isNotEmpty(legendTempKeys)){
            legendKeys = legendTempKeys;
        }

        // 防止多个xAxis为空字符串造成不唯一问题
        HashMap<String,Integer> legendKeyEmptyStringMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            String xAxisKey = jsonObject.getString("xAxis");
            String legendKey = jsonObject.getString("legend");
            String xAxisValue = xAxisValueMap.get(xAxisKey);
            String legendValue = legendValueMap.get(legendKey);
            legendValue = Objects.equals(legendValue, null) ? "" : legendValue;
            int endIndex = 0;
            if (((endIndex = legendValue.lastIndexOf("&")) != -1) && ((endIndex = legendValue.lastIndexOf("&",endIndex)) != -1)){
                legendValue = legendValue.substring(0,legendValue.lastIndexOf("&"));
            }
            xAxisValue = Objects.equals(xAxisValue, null) ? "" : xAxisValue;
            jsonObject.put("xAxis", xAxisValue);
            if (Objects.equals(AggTypeEnum.COUNT.getName(), legendKey)) {
                legendValue = legendKey;
            }
            jsonObject.put("legend", legendValue);
            String key = xAxisValue + "-" + legendValue;
            if ("".equals(xAxisValue)){
                Integer emptyStringIndex = legendKeyEmptyStringMap.get(legendKey);
                if (Objects.nonNull(emptyStringIndex)){
                    key = "&" + ++emptyStringIndex +  "-" + legendValue;
                    legendKeyEmptyStringMap.put(legendKey,emptyStringIndex);
                }else {
                    key = "&" + 0 +  "-" + legendValue;
                    legendKeyEmptyStringMap.put(legendKey,0);
                }

            }
            jsonArrayMap.put(key, jsonObject);
        }
        result.put("xAxis", xAxis);
        result.put("legend", legend);
        result.put("legendKeys", legendKeys);
        result.put("xAxisKeys", xAxisKeys);
    }

    String getSuffix(JSONObject jsonObject){
        FieldAttrPojo fieldAttrPojo = JSONObject.toJavaObject(JSONObject.parseObject(JSONObject.toJSONString(jsonObject)),FieldAttrPojo.class);
        if(Objects.equals(fieldAttrPojo.getFieldType(),FieldTypeEnum.COMPUTED_FIELD.getType())){
            String formula = fieldAttrPojo.getFormulaInfo().getString("formula");
            String formulaName = RegexUtil.extractFormulaName(formula);
            if (Objects.equals(formulaName,"DATE_DIFF")){
                String unit = DateDiffTypeEnum.DAY.getAlias();
                String textTemp = formula.substring(1,formula.length()-1);
                int startIndex;
                if (textTemp.lastIndexOf("}") < (startIndex = textTemp.lastIndexOf(","))){
                    unit = textTemp.substring(startIndex);
                }
                DateDiffTypeEnum typeEnum = DateDiffTypeEnum.getByAlias(unit);
                String suffix = typeEnum.getName();
                if (StringUtil.isNotEmpty(suffix)){
                    suffix = "(" + suffix + ")";
                }
                return suffix;
            }
        }
        return "";
    }

    /**
     * data组装
     *
     * @param xAxis         分类
     * @param legend        系列
     * @param jsonArrayMap  结果集
     * @param result        最终返回result集合
     * @param data          折线、面积、柱形图、叠加图、雷达等类型图的结果数据
     * @author zhouwq
     * @date 2019/4/12 10:25
     */
    private void chartDataRender(ChartEntity chartEntity,List<String> xAxisKeys,List<String> xAxis, List<String> legendKeys,List<String> legend, Map<String, JSONObject> jsonArrayMap, JSONObject result, List<ResultDataChartVO> data, JSONObject biaxialInfo, List<FieldAttrPojo> fieldAttrPojoList, int chartValueSize,DataWarningQueryListVO dataWarningQueryListVO) {
        Integer chartType = chartEntity.getChartType();
        FieldAttrPojo classifyAttr = JSON.parseArray(chartEntity.getChartClassify().toJSONString(), FieldAttrPojo.class).get(0);
        BiaxialInfoPojo biaxialInfoPojo = null;
        if (Objects.nonNull(biaxialInfo)){
            biaxialInfoPojo = JSONObject.parseObject(biaxialInfo.toJSONString(),BiaxialInfoPojo.class);
        }
        // 数据预警返回的数据不为null(历史预警)
        Map<String,List<ChartRlWarningPojo>> legendRlWarningMap = chartResultHelp.getLegendRlWarningMap(dataWarningQueryListVO,chartEntity,xAxisKeys);
        if (Objects.nonNull(legendRlWarningMap) && legendRlWarningMap.size()>0){
            // 是否是三层聚合
            Boolean flag = true;
            for (String s : legendKeys) {
                flag = s.indexOf("&" + PaasConstant.LEFT) == -1 && s.indexOf("&" + PaasConstant.RIGHT) == -1;
                if (!flag){
                    break;
                }
            }
            if (flag){
                Map<String,List<ChartRlWarningPojo>> tempMap = new HashMap<>();
                for (Map.Entry<String, List<ChartRlWarningPojo>> entry : legendRlWarningMap.entrySet()) {
                    String k = entry.getKey();
                    List<ChartRlWarningPojo> v = entry.getValue();
                    k = k.replaceAll("&"+ PaasConstant.LEFT ,"");
                    tempMap.put(k,v);
                }
                legendRlWarningMap = tempMap;
            }
        }
        int index = 0;
        JSONObject dataForm = null;
        Map<String,Integer> legendEmptyStringMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (int i = 0; i < legend.size(); i++) {
            String legendContrast = legend.get(i);
            String legendKey = legendKeys.size() > i ? legendKeys.get(i) : legendContrast;
            JSONArray legendArr = new JSONArray();
            index = i > (fieldAttrPojoList.size() - 1) ? (fieldAttrPojoList.size() - 1) : i;
            FieldAttrPojo fieldAttrPojo = fieldAttrPojoList.get(index);
            Integer fieldType = fieldAttrPojo.getFieldType();
            JSONArray advancedComputing = fieldAttrPojo.getAdvancedComputing();
            int accuracy = fieldAttrPojo.getAccuracy() == null ? 0 : fieldAttrPojo.getAccuracy();
            Integer groupingUsed = fieldAttrPojo.getGroupingUsed();
            Integer percentUsed = fieldAttrPojo.getPercentUsed();
            // 用百分比，数据计算精度加两位，符号统一由前端渲染
            if (Objects.equals(percentUsed, 1)) {
                accuracy += 2;
            }
            JSONObject dataFormSingle = new JSONObject();
            dataFormSingle.put("accuracy", accuracy);
            dataFormSingle.put("groupingUsed", groupingUsed);
            dataFormSingle.put("percentUsed", percentUsed);
            // 当前系列当前预警对应的预警值（当前预警）
            Map<Long,ChartRlWarningPojo> warningIdWarningPojoMap = new HashMap<>();
            // 是否同环比
            boolean isYearChain = chartResultHelp.isYearChain4Date(classifyAttr, advancedComputing);
            for (int j = 0; j < xAxis.size(); j++) {
                String xAxi = xAxis.get(j);
                String key = xAxi;
                if ("".equals(key)){
                    Integer emptyStringIndex = legendEmptyStringMap.get(legendKey);
                    if (Objects.nonNull(emptyStringIndex)){
                        key = "&" + ++emptyStringIndex;
                        legendEmptyStringMap.put(legendKey,emptyStringIndex);
                    }else {
                        key = "&" + 0;
                        legendEmptyStringMap.put(legendKey,0);
                    }

                }
                //将X轴和Y轴的key组装作为 唯一主键key
                JSONObject object = jsonArrayMap.get(key + "-" + DateDiffTypeEnum.removeSuffix(legendContrast));
                if (object != null) {
                    String countValue = "";
                    String value;
                    try {
                        if (fieldType.equals(FieldTypeEnum.COUNT.getType())) {
                            countValue = object.getString(ChartAggResultEnum.DOC_COUNT.getStr());
                            value = StringUtil.formatDouble(Double.valueOf(countValue), 0, 1);
                        } else {
                            countValue = object.getString(ChartAggResultEnum.COUNT.getStr());
                            value = StringUtil.formatDouble(Double.valueOf(countValue), accuracy, 1);
                        }
                        // 同环比处理
                        if (isYearChain) {
                            String oldVal = chartResultHelp.getOldValue4Chart(xAxisKeys, xAxis, jsonArrayMap, chartType, classifyAttr, legendContrast, advancedComputing, j, fieldType);
                            value = chartResultHelp.getYearChainValue(fieldAttrPojo, oldVal, value);
                        }
                        // 百分比
                        if (Objects.equals(percentUsed, 1) && Objects.nonNull(value) && !"".equals(value)) {
                            value = String.valueOf(new BigDecimal(value).multiply(new BigDecimal("100")));
                        }
                        // 获取单表当前预警
                        warningIdWarningPojoMap = chartResultHelp.getBLWarning(dataWarningQueryListVO,chartEntity,j,warningIdWarningPojoMap,value,fieldAttrPojo);
                        // 格式化小数位
                        value = StringUtil.formatDouble(Double.valueOf(value), accuracy, 1);
                    } catch (Exception e) {
                        value = countValue;
                    }
                    legendArr.add(value);
                } else {
                    //赋默认值
                    // 获取单表当前预警
                    warningIdWarningPojoMap = chartResultHelp.getBLWarning(dataWarningQueryListVO,chartEntity,j,warningIdWarningPojoMap,"0",fieldAttrPojo);
                    legendArr.add("0");
                }
            }
            ResultDataChartVO resultDataChartVO = new ResultDataChartVO(legendContrast, null, legendArr);

            // 有历史预警加上历史预警
//            String legendKey = legendKeys.get(i);
            if (Objects.nonNull(legendRlWarningMap.get(legendKey))){
                Set<Long> set = new HashSet<>();
                set.addAll(warningIdWarningPojoMap.keySet());

                if (warningIdWarningPojoMap.size()>0){
                    Map<Long, ChartRlWarningPojo> finalWarningIdWarningPojoMap = warningIdWarningPojoMap;
                    legendRlWarningMap.get(legendKey).forEach(item ->{
                        item.setData(new ArrayList<ChartRlWarningDataPojo>(){{
                            addAll(item.getData());
                            ChartRlWarningPojo pojo = finalWarningIdWarningPojoMap.get(item.getId());
                            if (Objects.nonNull(pojo)){
                                addAll(pojo.getData());
                            }
                        }});
                        set.remove(item.getId());
                    });
                }
                Map<Long, ChartRlWarningPojo> finalWarningIdWarningPojoMap = warningIdWarningPojoMap;
                Map<String, List<ChartRlWarningPojo>> finalLegendRlWarningMap = legendRlWarningMap;
                set.forEach(item ->{
                    finalLegendRlWarningMap.get(legendKey).add(finalWarningIdWarningPojoMap.get(item));});
                resultDataChartVO.setWarningValues(JSONArray.parseArray(JSON.toJSONString(legendRlWarningMap.get(legendKey))));
            }else {
                // 没有历史预警直接用当前预警
                if (warningIdWarningPojoMap.size()>0){
                    List<ChartRlWarningPojo> chartRlWarningPojos = new ArrayList<>();
                    warningIdWarningPojoMap.forEach((k,v) ->{
                        chartRlWarningPojos.add(v);
                    });
                    resultDataChartVO.setWarningValues(JSONArray.parseArray(JSON.toJSONString(chartRlWarningPojos)));
                }
            }
            if (Objects.nonNull(biaxialInfoPojo)){
                if (index < chartValueSize ){
                    if (Objects.equals(chartType,ChartTypeEnum.BIAXIAL_CHART.getCode())){
                        resultDataChartVO.setChartType(biaxialInfoPojo.getLeftChartType());
                    }else {
                        resultDataChartVO.setChartType(chartType);
                    }
                    resultDataChartVO.setYAxisName(biaxialInfoPojo.getLeftName());
                    resultDataChartVO.setYAxisIndex(0);
                }else {
                    if (Objects.equals(chartType,ChartTypeEnum.BIAXIAL_CHART.getCode())){
                        resultDataChartVO.setChartType(biaxialInfoPojo.getRightChartType());
                    }else {
                        resultDataChartVO.setChartType(chartType);
                    }
                    resultDataChartVO.setYAxisName(biaxialInfoPojo.getRightName());
                    resultDataChartVO.setYAxisIndex(1);
                }
            }
            // 设置千分符和百分比
            resultDataChartVO.setDataForm(dataFormSingle);
            if (Objects.isNull(dataForm)){
                dataForm = dataFormSingle;
            }
            resultDataChartVO.setFormId(fieldAttrPojo.getFormId());
            resultDataChartVO.setAttr(fieldAttrPojo.getAttr());
            resultDataChartVO.setOriginAttr(fieldAttrPojo.getOriginalAttr());
            data.add(resultDataChartVO);
        }
        result.put("data", data);
        result.put("dataForm", dataForm);
    }


    /**
     * dataSeries组装
     *
     * @param xAxis         系列（饼图分类作为系列）
     * @param legend        系列
     * @param jsonArrayMap  结果集
     * @param result        最终返回result集合
     * @param dataSeries    饼图、环图、仪表盘、地图、漏斗等类型图的结果数据
     * @param fieldAttrPojo 字段属性实体
     * @author zhouwq
     * @date 2019/4/12 10:25
     */
    private void chartDataSeriesRender(List<String> xAxis, List<String> legend, Map<String, JSONObject> jsonArrayMap, JSONObject result, List<ResultDataSeriesChartVO> dataSeries, FieldAttrPojo fieldAttrPojo) {
        // 字段类型code 判断是否为计数类型
        Integer fieldType = fieldAttrPojo.getFieldType();
        Integer accuracy = fieldAttrPojo.getAccuracy();
        accuracy = accuracy == null ? 2 : accuracy;
        Integer groupingUsed = fieldAttrPojo.getGroupingUsed();
        Integer percentUsed = fieldAttrPojo.getPercentUsed();
        // 用百分比，数据计算精度加两位，符号统一由前端渲染
        if (Objects.equals(percentUsed, 1)) {
            accuracy += 2;
        }
        JSONObject dataForm = new JSONObject();
        dataForm.put("accuracy", accuracy);
        dataForm.put("groupingUsed", groupingUsed);
        dataForm.put("percentUsed", percentUsed);
        for (String xAxisContrast : xAxis) {
            double sum = 0.0;
            boolean flag = false;
            String value = "";
            for (String legendContrast : legend) {
                String key = xAxisContrast + "-" + legendContrast;
                JSONObject object = jsonArrayMap.get(key);
                if (object != null) {
                    String xAxisValue = object.getString(ChartAggResultEnum.X_AXIS.getStr());
                    if (xAxisContrast.equals(xAxisValue)) {
                        String countValue;
                        if (fieldType.equals(FieldTypeEnum.COUNT.getType())) {
                            countValue = object.getString(ChartAggResultEnum.DOC_COUNT.getStr());
                            flag = true;
                        } else {
                            countValue = object.getString(ChartAggResultEnum.COUNT.getStr());
                        }
                        sum += Double.parseDouble(countValue);
                    }
                }
                ResultDataSeriesChartVO resultDataSeriesChartVO = new ResultDataSeriesChartVO();
                resultDataSeriesChartVO.setName(xAxisContrast);
                if (flag) {
                    value = StringUtil.formatDouble(sum, 0, 1);
                } else {
                    value = StringUtil.formatDouble(sum, accuracy, 1);
                }
                // 百分比
                if (Objects.equals(percentUsed, 1) && !"".equals(value)) {
                    value = String.valueOf(new BigDecimal(value).multiply(new BigDecimal("100")));
                }
                resultDataSeriesChartVO.setValue(value);
                dataSeries.add(resultDataSeriesChartVO);
            }
        }
        result.put("dataSeries", dataSeries);
        result.put("dataForm", dataForm);

    }

    /**
     * 渲染查询表
     *
     * @param tableHead   表头数据
     * @param entities    单表ES查询出来的数据
     * @param mulEntities 多表ES查询出来的数据
     * @return 整个表的数据
     * @author yuqian
     */
    private JSONObject encapsulateTableData(JSONArray tableHead, List<ChartFieldsAnalysisEntityExt> entities, List<StatisticBiFormDataEntity> mulEntities,
                                            ChartEntity chartEntity, Map<JSONObject, FieldAttrPojo> parseAttrMap, BaseDTO baseDTO) throws XbbException {
        JSONObject result = new JSONObject();
        JSONArray row = new JSONArray();
        JSONArray rowExplain = new JSONArray();
        List<JSONObject> headList = JSONObject.parseArray(tableHead.toJSONString(), JSONObject.class);
        result.put("customTitle", headList);
        //所有列的值map的集合
        List<List<String>> resultCol = new ArrayList<>();
        List<String> dataIdList = new ArrayList<>();
        JSONObject formIdAttr = chartEntity.getFormIdAttr();
        JSONArray filter = chartEntity.getFilter();
        boolean penetrateFlag = false;
        for (int i = 0; i < filter.size(); i++) {
            JSONObject jsonObject = filter.getJSONObject(i);
            if (Objects.equals(jsonObject.getInteger("penetrateFlag"), BasicConstant.ONE)) {
                penetrateFlag = true;
                break;
            }
        }
        //兼容特殊场景，就是产品子表产品编号、名称需要做一层转化，比如遇到产品编号或者产品名称或者产品编号、产品名称，但是我又不想没循环一个表头都要去查一次，所以我一次性查出来
        boolean subProductSelectTag = false;
        Map<Long, ProductEntityExt> productEntityExtMap = null;
        for (int i = 0; i < tableHead.size(); i++) {
            JSONObject dataObject = tableHead.getJSONObject(i);
            //兼容解析展现字段方法
            FieldAttrPojo fieldAttrPojo = parseAttrMap.get(dataObject);
            //特殊处理address 字段
            Integer type = fieldAttrPojo.getFieldType();
            String attr = fieldAttrPojo.getAttr();
            //如果是经销商档案的计算方式
            boolean settlementMethod = false;
            if (DistributorEnum.SETTLEMENT_METHOD.getSaasAttr().equals(fieldAttrPojo.getSaasAttr())) {
                settlementMethod = true;
            }
            Long formId = fieldAttrPojo.getFormId();
            JSONObject attrMapping = new JSONObject();
            if (formIdAttr != null && formIdAttr.size() > 0) {
                attrMapping = formIdAttr.getJSONObject(formId.toString());
            }
            String key = dataObject.getString("key");
            String[] keySplit = key.split("&");
            List<String> values = new ArrayList<>();
            JSONObject tableData = new JSONObject();
            Map<String, String> dataIdToEsId = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            if (CollectionsUtil.isNotEmpty(entities)) {
                for (ChartFieldsAnalysisEntityExt entityExt : entities) {
                    //ID录入只初始化一次
                    if (i == 0) {
                        dataIdList.add(entityExt.getDataId().toString());
                    }
                    if (FieldTypeEnum.ADDRESS.equals(FieldTypeEnum.getFieldTypeEnum(type)) && penetrateFlag) {
                        String addressList = keySplit[0];
                        String[] addressArray = addressList.split("\\.");
                        attr = addressArray[0];
                    }
                    if (!EsUtil.setInData(type)) {
                        //团队特殊处理 需要传dataID 从team中获取团队信息
                        Object outData = EsHelper.isTeamLogicByFieldType(type, fieldAttrPojo.getBusinessType()) ? entityExt.getDataId() : ReflectHelper.valueGet(entityExt, attr, true);
                        //避免空指针
                        outData = outData == null ? "" : outData;
                        values.add(outData.toString());
                    } else {
                        String value = null;
                        //type类型为checkbox_group,且isRedundant为0时 为执行人字段 需传dataId作为value
                        if (Objects.equals(FieldTypeEnum.CHECKBOX_GROUP.getType(), type) && Objects.equals(0, fieldAttrPojo.getIsRedundant()) && !settlementMethod) {
                            value = entityExt.getDataId().toString();
                        } else {
                            JSONObject data = entityExt.getData();
                            if (data == null || data.size() == 0) {
                                //ES data 里面的数据是null 自动给他默认值""
                                if (Objects.equals(FieldTypeEnum.COMPUTED_FIELD.getType(),type)) {
                                    value = getComputedValue(fieldAttrPojo, entityExt, value);
                                }else{
                                    value = "";
                                }
                            } else {
                                //子表单取值特殊处理
                                if (FieldTypeEnum.isSubFormType(type)) {
                                    JSONArray subFormJson = data.getJSONArray(attr);
                                    value = subFormJson == null || subFormJson.size() == BasicConstant.ZERO ? "" : subFormJson.toJSONString();
                                }
                                //关联字段 回显
                                else if (Objects.equals(fieldAttrPojo.getFieldType(), FieldTypeEnum.LINK_BUSINESS_SINGLE.getType()) || Objects.equals(fieldAttrPojo.getFieldType(), FieldTypeEnum.LINK_BUSINESS_MULTI.getType())
                                        || Objects.equals(fieldAttrPojo.getFieldType(), FieldTypeEnum.LINK_RECEIVER.getType())) {
                                    value = data.getString(fieldAttrPojo.getLinkedText());
                                }
                                //客户生日取值特殊处理
                                else if (FieldTypeEnum.BIRTHDAY.getType().equals(type)) {
                                    value = getBirthday(fieldAttrPojo, data, attr);
                                } else {
                                    // List Map类型判断
                                    if ((data.get(attr) instanceof List)) {
                                        List list = data.getObject(attr, List.class);
                                        StringBuilder str = new StringBuilder();
                                        if (list != null && list.size() > 0) {
                                            for (Object obj : list) {
                                                str.append(obj).append(",");
                                            }
                                            if (str.length() > 0) {
                                                str.deleteCharAt(str.length() - 1);
                                            }
                                        }
                                        value = str.toString();
                                    } else if ((data.get(attr) instanceof Map)) {
                                        if (type.equals(FieldTypeEnum.ADDRESS.getType())) {
                                            JSONObject jsonObject = data.getJSONObject(attr);
                                            String provinceStr = jsonObject.getString(BusinessConstant.PROVINCE) == null ? "" : jsonObject.getString(BusinessConstant.PROVINCE);
                                            String cityStr = jsonObject.getString(BusinessConstant.CITY) == null ? "" : jsonObject.getString(BusinessConstant.CITY);
                                            String districtStr = jsonObject.getString(BusinessConstant.DISTRICT) == null ? "" : jsonObject.getString(BusinessConstant.DISTRICT);
                                            String addressStr = jsonObject.getString(BusinessConstant.ADDRESS) == null ? "" : jsonObject.getString(BusinessConstant.ADDRESS);
                                            value = provinceStr + cityStr + districtStr + addressStr;
                                        } else {
                                            value = JSONObject.toJSONString(data.get(attr));
                                        }
                                    } else {
                                        value = data.getString(attr);
                                        // 特殊处理一下数字类型的值，原因是可能值为int或double类型
                                        if (FieldTypeEnum.numFieldType(type)) {
                                            Double valueDouble = data.getDouble(attr);
                                            if (Objects.nonNull(valueDouble)) {
                                                value = valueDouble.toString();
                                            }
                                        }
                                        if (Objects.equals(FieldTypeEnum.COMPUTED_FIELD.getType(),type)) {
                                            value = getComputedValue(fieldAttrPojo, entityExt, value);
                                        }
                                    }
                                }
                            }
                        }
                        values.add(value);
                    }
                }
            } else if (CollectionsUtil.isNotEmpty(mulEntities)) {
                //因为恶心的需求，就是产品名称和产品编号希望拿到最新的值，但是产品子表单表中存的只是历史数据，所以这边需要要用产品id重新去产品表中拿最新的数据，建仓那边也只是存产品id
                String attrKey = keySplit[0];
                String transferNoAttrKey = attrMapping.getString(BISubProductCommonFieldEnum.PRODUCT_NO.getAttr());
                String transferNameAttrKey = attrMapping.getString(BISubProductCommonFieldEnum.PRODUCT_NAME.getAttr());
                boolean specialSubProductFieldTag = Objects.nonNull(fieldAttrPojo.getBusinessType()) && BIProductReformEnum.getProductSubBusList().contains(fieldAttrPojo.getBusinessType());
                if (specialSubProductFieldTag && !subProductSelectTag) {
                    Set<Long> productIdSet = new HashSet<>();
                    attrKey = keySplit[0];
                    if (Objects.equals(attrKey, transferNoAttrKey) || Objects.equals(attrKey, transferNameAttrKey)) {
                        for (StatisticBiFormDataEntity statisticBiFormDataEntity : mulEntities) {
                            //通过反射去获取值
                            String productIdStr = (String)(ReflectHelper.valueGet(statisticBiFormDataEntity, attrKey));
                            if (StringUtil.isNotEmpty(productIdStr)) {
                                Long productId = Long.parseLong(productIdStr);
                                productIdSet.add(productId);
                            }
                        }
                        if (CollectionsUtil.isNotEmpty(productIdSet)) {
                            productEntityExtMap = productModel.getProductMapByIds(chartEntity.getCorpid(), new ArrayList<>(productIdSet), null,
                                    Arrays.asList(BasicConstant.ID, BasicConstant.SERIAL_NO, ProductEnum.getAttrConnectData(ProductEnum.NAME)));
                            subProductSelectTag = true;
                        }
                    }

                }
                for (StatisticBiFormDataEntity statisticPaasFormDataEsEntity : mulEntities) {
                    //ID录入只初始化一次
                    if (i == 0) {
                        dataIdList.add(statisticPaasFormDataEsEntity.getEsId());
                    }
                        if (FieldTypeEnum.ADDRESS.equals(FieldTypeEnum.getFieldTypeEnum(fieldAttrPojo.getFieldType())) && penetrateFlag) {
                            String addressList = keySplit[0];
                            String[] addressArray = addressList.split("\\.");
                            attr = addressArray[0];
                        }
                        if (!EsUtil.setInData(type)) {
                            Object outData;
                            if (EsHelper.isTeamLogicByFieldType(type, fieldAttrPojo.getBusinessType())) {
                                processTeamField(values, chartEntity, formId, statisticPaasFormDataEsEntity, Objects.equals(FieldTypeEnum.OWNERID.getType(), type));
                                continue;
                            } else {
                                outData = ReflectHelper.valueGet(statisticPaasFormDataEsEntity, keySplit[0]);
                            }
                            outData = outData == null ? "" : outData;
                            values.add(outData.toString());
                        } else {
                            String value = null;
                            if (StringUtil.isNotEmpty(attrKey) && (StringUtil.isNotEmpty(transferNoAttrKey)
                                    && Objects.equals(attrKey, transferNoAttrKey) && specialSubProductFieldTag)
                                    && Objects.nonNull(productEntityExtMap)) {
                                Object productIdValue = ReflectHelper.valueGet(statisticPaasFormDataEsEntity, attrKey);
                                if (Objects.nonNull(productIdValue)) {
                                    //代表是编号
                                    ProductEntityExt productSerialNoEntityExt = productEntityExtMap.get(Long.parseLong((String)productIdValue));
                                    if (Objects.isNull(productSerialNoEntityExt)) {
                                        value = "";
                                    }else {
                                        value = productSerialNoEntityExt.getSerialNo();
                                    }
                                }
                            } else if (StringUtil.isNotEmpty(attrKey) && (StringUtil.isNotEmpty(transferNameAttrKey)
                                && Objects.equals(attrKey, transferNameAttrKey) && specialSubProductFieldTag)
                                && Objects.nonNull(productEntityExtMap)) {
                                Object productNameValue = ReflectHelper.valueGet(statisticPaasFormDataEsEntity, attrKey);
                                if (Objects.nonNull(productNameValue)) {
                                    //代表是名称
                                    ProductEntityExt productNameEntityExt = productEntityExtMap.get(Long.parseLong((String)productNameValue));
                                    if (Objects.isNull(productNameEntityExt)) {
                                        value = "";
                                    }else {
                                        value = productNameEntityExt.getData().getString(ProductEnum.NAME.getAttr());
                                    }
                                }
                            }else if (Objects.equals(FieldTypeEnum.CHECKBOX_GROUP.getType(), type) && Objects.equals(0,fieldAttrPojo.getIsRedundant())) {
                                value = ReflectHelper.valueGet(statisticPaasFormDataEsEntity, attrMapping.getString(StringConstant.DATA_ID)).toString();
                            } else {
                                Object valueObj = ReflectHelper.valueGet(statisticPaasFormDataEsEntity, attr);
                                if (valueObj == null) {
                                    value = "";
                                } else {
                                    //子表单取值特殊处理
                                    if (FieldTypeEnum.isSubFormType(type)) {
                                        JSONArray subFormJson = (JSONArray) valueObj;
                                        value = subFormJson.size() == BasicConstant.ZERO ? "" : subFormJson.toJSONString();
                                    }
                                    //关联字段 回显
                                    else if (Objects.equals(fieldAttrPojo.getFieldType(), FieldTypeEnum.LINK_BUSINESS_SINGLE.getType()) || Objects.equals(fieldAttrPojo.getFieldType(), FieldTypeEnum.LINK_BUSINESS_MULTI.getType())) {
                                        Object outData = ReflectHelper.valueGet(statisticPaasFormDataEsEntity, fieldAttrPojo.getLinkedText());
                                        if (outData != null) {
                                            value = outData.toString();
                                        }
                                    }
                                    //客户生日取值特殊处理
                                    else if (FieldTypeEnum.BIRTHDAY.getType().equals(type)) {
                                        value = getBirthday(fieldAttrPojo, statisticPaasFormDataEsEntity, attr);
                                    } else {
                                        if ((valueObj instanceof List)) {
                                            List list = (List) valueObj;
                                            StringBuilder str = new StringBuilder();
                                            if (list.size() > 0) {
                                                for (Object obj : list) {
                                                    str.append(obj).append(",");
                                                }
                                                if (str.length() > 0) {
                                                    str.deleteCharAt(str.length() - 1);
                                                }
                                            }
                                            value = str.toString();
                                        } else if ((valueObj instanceof Map)) {
                                            if (type.equals(FieldTypeEnum.ADDRESS.getType())) {
                                                JSONObject jsonObject = (JSONObject) valueObj;
                                                String provinceStr = jsonObject.getString(BusinessConstant.PROVINCE) == null ? "" : jsonObject.getString(BusinessConstant.PROVINCE);
                                                String cityStr = jsonObject.getString(BusinessConstant.CITY) == null ? "" : jsonObject.getString(BusinessConstant.CITY);
                                                String districtStr = jsonObject.getString(BusinessConstant.DISTRICT) == null ? "" : jsonObject.getString(BusinessConstant.DISTRICT);
                                                String addressStr = jsonObject.getString(BusinessConstant.ADDRESS) == null ? "" : jsonObject.getString(BusinessConstant.ADDRESS);
                                                value = provinceStr + cityStr + districtStr + addressStr;
                                            } else {
                                                value = JSONObject.toJSONString(valueObj);
                                            }
                                        } else {
                                            value = valueObj.toString();
                                        }
                                    }
                                }
                            }
                            values.add(value);
                        }
                }

            }
            Map<String, String> parseDataMap = null;
            if (FieldTypeEnum.isSubFormType(type)) {
                parseDataMap = chartResultHelp.getSubFormMap(fieldAttrPojo, values, chartEntity, baseDTO);
            } else if (Objects.equals(fieldAttrPojo.getFieldType(), FieldTypeEnum.LINK_BUSINESS_SINGLE.getType()) || Objects.equals(fieldAttrPojo.getFieldType(), FieldTypeEnum.LINK_BUSINESS_MULTI.getType())
                    || FieldTypeEnum.BIRTHDAY.getType().equals(type)) {
                parseDataMap = chartResultHelp.assembleDataMap(values);
            } else if (Objects.equals(fieldAttrPojo.getFieldType(), FieldTypeEnum.AREA.getType())){
                parseDataMap = chartResultHelp.distributorAreaMap(chartEntity.getCorpid());
            } else {
                parseDataMap = valueListAnalysis(fieldAttrPojo,chartEntity.getCorpid(),values,chartEntity, dataIdToEsId, baseDTO);
            }
//            if (Objects.equals(fieldAttrPojo.getFieldType(), FieldTypeEnum.OWNERID.getType()) || Objects.equals(fieldAttrPojo.getFieldType(), FieldTypeEnum.COUSERID.getType())
//                    || Objects.equals(fieldAttrPojo.getFieldType(), FieldTypeEnum.CREATORID.getType()) || Objects.equals(fieldAttrPojo.getFieldType(), FieldTypeEnum.USER_GROUP.getType())
//                    || Objects.equals(fieldAttrPojo.getFieldType(), FieldTypeEnum.USER.getType())) {
//                Set<String> userIds = parseDataMap.keySet();
//                Map<String, Object> param = new HashMap<>();
//                param.put("userIdIn",userIds);
//                param.put("corpid",chartEntity.getCorpid());
//                param.put(ParameterConstant.COLUMNS, "user_id, name");
//                param.put(ParameterConstant.LEAVE_MARKS,BasicConstant.ONE);
//                List<UserEntity> userList = userModel.findEntitys(param);
//                parseDataMap.clear();
//                for (UserEntity userEntity : userList) {
//                    parseDataMap.put(userEntity.getUserId(),userEntity.getName());
//                }
//            }
            tableData.put(key, parseDataMap);
            rowExplain.add(fieldAttrPojo);
            row.add(tableData);
            //做为二位数组 放入查询表的值
            resultCol.add(values);
        }
        List<JSONObject> dataList = JSONObject.parseArray(row.toJSONString(), JSONObject.class);
        JSONArray queryTableResult = chartResultHelp.queryTableAssemble(resultCol, dataList,rowExplain);
        for (int i = 0; i < queryTableResult.size(); i++) {
            JSONObject jsonObject = queryTableResult.getJSONObject(i);
            jsonObject.put("id", dataIdList.get(i));
        }
        result.put("customData", queryTableResult);
        if (dataList.size() > ChartConstant.MAX_SIZE) {
            result.put("customData", queryTableResult.subList(0, ChartConstant.MAX_SIZE));
        }
        return result;
    }

    private static String getComputedValue(FieldAttrPojo fieldAttrPojo, ChartFieldsAnalysisEntityExt entityExt, String value) {
        String tempAttr = fieldAttrPojo.getAttr();
        //根据当前计算字段的attr决定调用哪个
        Object tempObject = null;
        switch (tempAttr) {
            case "computedField_1":
                tempObject = entityExt.getComputedField_1();
                break;
            case "computedField_2":
                tempObject = entityExt.getComputedField_2();
                break;
            case "computedField_3":
                tempObject = entityExt.getComputedField_3();
                break;
            case "computedField_4":
                tempObject = entityExt.getComputedField_4();
                break;
            case "computedField_5":
                tempObject = entityExt.getComputedField_5();
                break;
            case "computedField_6":
                tempObject = entityExt.getComputedField_6();
                break;
            case "computedField_7":
                tempObject = entityExt.getComputedField_7();
                break;
            case "computedField_8":
                tempObject = entityExt.getComputedField_8();
                break;
            case "computedField_9":
                tempObject = entityExt.getComputedField_9();
                break;
            case "computedField_10":
                tempObject = entityExt.getComputedField_10();
                break;
            default:
                break;
        }
        if (Objects.nonNull(tempObject)) {
            double tempDouble = Double.parseDouble(tempObject.toString());
            value = String.format("%.2f", tempDouble);
        }
        return value;
    }

    /**
     * 汇总数据组装
     *
     * @param attrArray        汇总的数据
     * @return 整个表的数据
     */
    private Map<String, String> countAttrAssemble(JSONArray attrArray, JSONObject formIdAttr, SearchSourceBuilder sourceBuilder, Map<String, FieldAttrPojo> parseAttrMap, Boolean isSingle) throws XbbException {
        Map<String, String> map = new HashMap<>(16);
        if (!attrArray.isEmpty()) {
            // String[] fields = new String[attrArray.size()];
            for (int i = 0; i < attrArray.size(); i++) {
                JSONObject jsonObject = attrArray.getJSONObject(i);
                String attr = jsonObject.getString("attr");
                Integer type = null;
                if (jsonObject.containsKey("fieldType")) {
                    type = jsonObject.getInteger("fieldType");
                }
                if (FieldTypeEnum.isSubFormType(type)) {
                    JSONObject subFormObj = jsonObject.getJSONObject("subForm");
                    if (subFormObj != null) {
                        JSONArray items = subFormObj.getJSONArray("items");
                        for (int x = 0; x < items.size(); x++) {
                            JSONObject object = items.getJSONObject(x);
                            object.put("attr", attr + StringConstant.POINT + object.getString("attr"));
                        }
                        map.putAll(countAttrAssemble(items, formIdAttr, sourceBuilder, parseAttrMap, isSingle));
                        continue;
                    }
                }
                String field = EsUtil.setInData(type) && isSingle ? "data." + attr : attr;
                map.put(field, attr + "&" + type);
                FieldAttrPojo fieldAttrEntity = JSONObject.parseObject(jsonObject.toJSONString(), FieldAttrPojo.class);
                parseAttrMap.put(field, fieldAttrEntity);
                AggTypeEnum aggTypeEnum = AggTypeEnum.getByAlias(fieldAttrEntity.getAggType());
                if (Objects.equals(FieldTypeEnum.COMPUTED_FIELD.getType(),type)) {
                    List<String> fieldsList = new ArrayList<>();
                    //判断单表还是多表，拼script
                    JSONObject formulaInfo = fieldAttrEntity.getFormulaInfo();
                    String formula = formulaInfo.getString("formula");
                    //公式转换
                    try {
                        formula = EsUtil.getString(sourceBuilder, formIdAttr, isSingle, fieldsList, formulaInfo, formula, Long.toString(fieldAttrEntity.getFormId()));
                    } catch (XbbException e) {
                        LOG.error("计算字段的公式格式有问题", e);
                        throw e;
                    }
                    switch (aggTypeEnum) {
                        case MAX:
                            MaxAggregationBuilder maxAggregationBuilder = AggregationBuilders.max(field).script(new Script(formula));
                            sourceBuilder.aggregation(maxAggregationBuilder);
                            break;
                        case MIN:
//                            MinAggregationBuilder minAggregationBuilder = AggregationBuilders.min(field).script(new Script(text));
                            MinAggregationBuilder minAggregationBuilder = AggregationBuilders.min(field).script(new Script(formula));
                            sourceBuilder.aggregation(minAggregationBuilder);
                            break;
                        case SUM:
                            SumAggregationBuilder sumAggregationBuilder = AggregationBuilders.sum(field).script(new Script(formula));
                            sourceBuilder.aggregation(sumAggregationBuilder);
                            break;
                        case AVG:
                            AvgAggregationBuilder avgAggregationBuilder = AggregationBuilders.avg(field).script(new Script(formula));
                            sourceBuilder.aggregation(avgAggregationBuilder);
                            break;
                        case COUNT:
                            ValueCountAggregationBuilder countAggregationBuilder = AggregationBuilders.count(field).script(new Script(formula));
                            sourceBuilder.aggregation(countAggregationBuilder);
                            break;
                        default:
                            break;
                    }

                }else {
                    switch (aggTypeEnum) {
                        case MAX:
                            MaxAggregationBuilder aggregationBuilder = AggregationBuilders.max(field).field(field);
                            sourceBuilder.aggregation(aggregationBuilder);
                            break;
                        case MIN:
                            MinAggregationBuilder minAggregationBuilder = AggregationBuilders.min(field).field(field);
                            sourceBuilder.aggregation(minAggregationBuilder);
                            break;
                        case SUM:
                            SumAggregationBuilder sumAggregationBuilder = AggregationBuilders.sum(field).field(field);
                            sourceBuilder.aggregation(sumAggregationBuilder);
                            break;
                        case AVG:
                            AvgAggregationBuilder avgAggregationBuilder = AggregationBuilders.avg(field).field(field);
                            sourceBuilder.aggregation(avgAggregationBuilder);
                            break;
                        case COUNT:
                            ValueCountAggregationBuilder countAggregationBuilder = AggregationBuilders.count(field).field(field);
                            sourceBuilder.aggregation(countAggregationBuilder);
                            break;
                        default:
                            break;
                    }
                }
            }
        }
        return map;
    }

    /**
     * 查询表的自定义展现数据
     *
     * @param fieldAttrPojoList 需要解析的字段列表
     * @param tableHead         表头的数据
     */
    private void displayAttrAssemble(List<FieldAttrPojo> fieldAttrPojoList, List<FieldAttrPojo> summaryAttrList, SearchSourceBuilder sourceBuilder
            , JSONArray tableHead, Map<JSONObject, FieldAttrPojo> parseAttrMap, Map<String, FieldAttrPojo> summaryAttrMap, ChartEntity chartEntity) throws XbbException {
        //子表单处理
        List<String> fieldsList = new ArrayList<>();
        //查询表若只选择负责人/协同人时 需要取到对应的dataId 作为查询条件
        Boolean isSingle = EsUtil.getSingle(chartEntity);
        JSONObject formIdAttr = chartEntity.getFormIdAttr();
        if (isSingle) {
            fieldsList.add(FieldTypeEnum.DATAID.getAlias());
        } else {
            formIdAttr.forEach((key, value) -> {
                JSONObject valueObj = (JSONObject) value;
                fieldsList.add(valueObj.getString(StringConstant.DATA_ID));
            });
        }
        //esId 团队处理需求
        fieldsList.add("esId");
        if (CollectionsUtil.isNotEmpty(fieldAttrPojoList)) {
            for (FieldAttrPojo fieldAttrPojo : fieldAttrPojoList) {
                //遍历displayAttr
                Integer fieldType = fieldAttrPojo.getFieldType();
                String attr = fieldAttrPojo.getAttr();
                JSONObject headName = new JSONObject();
                String label = fieldAttrPojo.getLabel();
                String labelName = fieldAttrPojo.getLabelName();
                String attrName = fieldAttrPojo.getAttrName();
                if (Objects.equals(chartEntity.getChartType(), ChartTypeEnum.PK_CUSTOM.getCode())) {
                    // 自定义pk
                    headName.put("name", attrName);
                } else if (fieldAttrPojo.getAggType() != null) {
                    // 查询表，汇总字段也会加到表头字段中，所以查询汇总方式
                    AggTypeEnum aggTypeEnum = AggTypeEnum.getByAlias(fieldAttrPojo.getAggType());
                    if (Objects.equals(FieldTypeEnum.SUB_FORM.getType(),fieldType)) {
                        if (Objects.equals(labelName,label)){
                            headName.put("name", attrName + "(" + aggTypeEnum.getName() + ")");
                        }else{
                            headName.put("name", labelName + "(" + aggTypeEnum.getName() + ")");
                        }
                    }else{
                        if (Objects.equals(labelName,label)){
                            String temp = Arrays.asList(label.split("--")).get(0) + "--" + attrName;
                            headName.put("name", temp+ "(" + aggTypeEnum.getName() + ")");
                        }else{
                            headName.put("name", labelName + "(" + aggTypeEnum.getName() + ")");
                        }
                    }
                } else {
                    if (Objects.equals(FieldTypeEnum.SUB_FORM.getType(),fieldType)) {
                        if (Objects.equals(labelName,label)){
                            String s = Arrays.asList(label.split("--")).get(0);
                            headName.put("name",s + "--" + attrName);
                        }else{
                            headName.put("name", labelName);
                        }
                    }else{
                        if (Objects.equals(FieldTypeEnum.COMPUTED_FIELD.getType(),fieldType)) {
                            headName.put("name",Arrays.asList(labelName.split("--")).get(0));
                        }else{
                            if (Objects.equals(labelName,label)){
                                String temp = Arrays.asList(label.split("--")).get(0) + "--" + attrName;
                                headName.put("name",temp);
                            }else{
                                headName.put("name", labelName);
                            }
                        }
                    }
                }
                headName.put("frozeKey", fieldAttrPojo.getFormId() + attr);
                headName.put("key", attr + "&" + fieldAttrPojo.getFieldType());
                headName.put("formId", fieldAttrPojo.getFormId());
                headName.put("fieldType", fieldAttrPojo.getFieldType());
                headName.put("columnFlag", fieldAttrPojo.getColumnFlag());
                if (fieldAttrPojo.getDateGroupType() != null) {
                    headName.put("dateGroupType", fieldAttrPojo.getDateGroupType());
                }
                specialTableTitleHandle(fieldAttrPojo, fieldsList, headName, isSingle, chartEntity);
                tableHead.add(headName);
                if (Objects.equals(FieldTypeEnum.COMPUTED_FIELD.getType(),fieldType)) {
                    List<String> tempFieldsList = new ArrayList<>();
                    //判断单表还是多表，拼script
                    JSONObject formulaInfo = fieldAttrPojo.getFormulaInfo();
                    String formula = formulaInfo.getString("formula");
                    try {
                        formula = EsUtil.getString(sourceBuilder, formIdAttr, isSingle, tempFieldsList, formulaInfo, formula, Long.toString(fieldAttrPojo.getFormId()));
                        formulaInfo.put("formula",formula);
                        fieldAttrPojo.setFormulaInfo(formulaInfo);
                    } catch (XbbException e) {
                        LOG.error("计算字段的公式格式有问题", e);
                        throw e;
                    }
                    sourceBuilder.scriptField(fieldAttrPojo.getAttr(),new Script(formula));
                    fieldsList.add(fieldAttrPojo.getAttr());
                }else{
                    fieldsList.add(EsUtil.setInData(fieldAttrPojo.getFieldType()) && isSingle ? "data." + attr : attr);
                    if (Objects.equals(fieldAttrPojo.getFieldType(), FieldTypeEnum.LINK_BUSINESS_SINGLE.getType()) || Objects.equals(fieldAttrPojo.getFieldType(), FieldTypeEnum.LINK_BUSINESS_MULTI.getType())
                        || Objects.equals(fieldAttrPojo.getFieldType(), FieldTypeEnum.LINK_RECEIVER.getType())) {
                        fieldsList.add(EsUtil.setInData(fieldAttrPojo.getFieldType()) && isSingle ? "data." + fieldAttrPojo.getLinkedText() : fieldAttrPojo.getLinkedText());
                    }
                }
                parseAttrMap.put(headName, fieldAttrPojo);
            }
        }
        if (summaryAttrList != null) {
            for (FieldAttrPojo fieldAttrPojo : summaryAttrList) {
                String labelName = fieldAttrPojo.getLabelName();
                Long formId = fieldAttrPojo.getFormId();
                String attr = fieldAttrPojo.getAttr();
                Integer fieldType = fieldAttrPojo.getFieldType();
                AggTypeEnum aggTypeEnum = AggTypeEnum.getByAlias(fieldAttrPojo.getAggType());
                JSONObject headName = new JSONObject();
                headName.put("name", labelName + "(" + aggTypeEnum.getName() + ")");
                //多表以及计数字段需要加formId做标识
                String key = attr.contains("count") && !isSingle ? formId + attr + "&" + fieldType : attr + "&" + fieldType;
                headName.put("key", key);
                headName.put("formId", formId);
                headName.put("fieldType", fieldType);
                headName.put("summaryAttr", 1);
                tableHead.add(headName);
                parseAttrMap.put(headName, fieldAttrPojo);
                if (summaryAttrMap != null) {
                    summaryAttrMap.put(attr + "&" + fieldType, fieldAttrPojo);
                }
            }
        }
        String[] fields = new String[fieldsList.size()];
        fields = fieldsList.toArray(fields);
        if (sourceBuilder != null) {
            sourceBuilder.fetchSource(fields, null);
        }
    }
    /**
     * 图表的自定义展现数据,字段拼接
     *
     * @param fieldAttr  字段属性
     * @param isSingle 是否为单表
     * @author zhouwq
     * @date 2019/4/12 10:29
     */
    private static String chartAttrAssemble(FieldAttrPojo fieldAttr, Boolean isSingle) {
        String saasAttr = fieldAttr.getSaasAttr();
        Integer fieldType = fieldAttr.getFieldType();
        String field = EsUtil.setInData(fieldType) && isSingle ? "data." + fieldAttr.getAttr() : fieldAttr.getAttr();
        if (!Objects.equals(saasAttr, CustomerManagementEnum.IS_ARCHIVED.getSaasAttr()) && !Objects.equals(saasAttr, CustomerManagementEnum.IS_PUBLIC.getSaasAttr())
                && !Objects.equals(saasAttr, ContractPerformanceEnum.IS_SIGN.getSaasAttr())) {
            field = EsUtil.addKeyWord(fieldType, field);
        }
        return field;
    }

    /**
     * 获取单个数值统计结果（如首页看板，客户模块总数统计，自定义单个数值统计等）
     *
     * @param chartEntity     图表实体
     * @param chartResultPojo
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartResultValueDetailVO
     * @throws XbbException ES查询时抛出的异常
     * @author 徐俊杰
     * @date 2019/3/12 15:47
     * @since v1.0
     */
    private ChartResultValueDetailVO getResultValue(ChartEntity chartEntity, ChartResultPojo chartResultPojo) throws XbbException {
        ChartResultValueDetailVO chartResultValueDetailVO = new ChartResultValueDetailVO();
        chartResultPojo.setChartEntity(chartEntity);
        //图表的其他参数（结果值以外）
        BeanUtil.copyProperties(chartEntity, chartResultValueDetailVO);
        boolean thousandSwitch = chartResultPojo.isThousandSwitch();
        //判断是系统图表还是自定义图表
        StatisticsTypeEnum statisticsTypeEnum = StatisticsTypeEnum.getByCode(chartEntity.getStatisticsType());
        String total = "";
        //自定义的存的为英文
        String unitTemp = chartEntity.getUnit();
        switch (statisticsTypeEnum) {
            case SYSTEM_STATISTIC:
                SystemCodeEnum systemCodeEnum = SystemCodeEnum.getByCode(chartEntity.getSystemCode());
                if (systemCodeEnum != null) {
                    if (SystemCodeEnum.noThousandSwitch(systemCodeEnum)) {
                        chartResultPojo.setThousandSwitch(false);
                    }
                    String unit = ChartResultUtil.formatUnit(thousandSwitch, unitTemp);
                    //把系统枚举systemCodeEnum置入chartResultPojo
                    chartResultPojo.setSystemCodeEnum(systemCodeEnum);
                    // 数值格式
                    if (Objects.equals(systemCodeEnum.getHasAmount(), 1)) {
                        Integer numFormat = chartEntity.getNumFormat();
                        chartResultPojo.setNumFormat(numFormat);
                        NumFormatEnum numFormatEnum = NumFormatEnum.getByCode(numFormat);
                        unit = numFormatEnum.getUnit();
                        chartResultPojo.setUnit(unit);
                        chartEntity.setUnit(unit);
                    }
                    chartResultValueDetailVO.setUnit(unit);
                    //计算结果值
                    ChartResultProService chartResultProService = chartStrategyFactory.getChartResultProService(systemCodeEnum.getXbbRefTypeEnum().getCode());
                    if (Objects.isNull(chartResultProService)){
                        chartResultProService = chartStrategyFactory.getChartResultProService(BasicConstant.ZERO);
                    }
                    total = (String) chartResultProService.getResult4System(ReturnTypeEnum.VALUE_RETURN, systemCodeEnum.getXbbRefTypeEnum(), chartResultPojo, null);
                    ThroughDTO throughDTO = null;
                    if (systemCodeEnum != SystemCodeEnum.PRODUCT_COST_BOARD && systemCodeEnum != SystemCodeEnum.QUOTATION_CONVERSION_BOARD) {
                        //首页当前库存成本不能穿透
                        throughDTO = new ThroughDTO(chartResultPojo, systemCodeEnum);
                    }
                    TimePojo timePojo = throughHelp.formatThroughTimeInfo(false, chartResultPojo.getFiscalYearTimePojo(), chartResultPojo.getStartTime(), chartResultPojo.getEndTime());
                    String through = throughHelp.getThrough(throughDTO, timePojo);
                    chartResultValueDetailVO.setThrough(through);
                    ChartResultUtil.dealWithGroupIconColor(chartResultValueDetailVO, systemCodeEnum);
                }
                break;
            case CUSTOM_STATISTIC:
                //自定义单位的展示
                String unit = customHelp.setUnit(chartEntity);
                //获取自定义指标
                total = getCustomResultValue(chartEntity, chartResultPojo);
                if ("".equals(total)) {
                    total = "0";
                } else {
                    Double valueDouble = StringUtil.toDouble(total, 0D);
                    if (Objects.equals(UnitEnum.NUMBER.getAlias(), unitTemp)) {
                        total = StringUtil.formatDouble(valueDouble, 0, 1);
                    } else if (Objects.equals(UnitEnum.MONEY.getAlias(), unitTemp)) {
                        total = ChartResultUtil.formatValue2Double(false, ValueTypeEnum.VALUE_MONEY, thousandSwitch, valueDouble, NumFormatEnum.DEFAULT, false);
                        unit = ChartResultUtil.formatUnit(thousandSwitch, unit);
                    } else {
                        //统一取小数点后两位
                        total = StringUtil.formatDouble(valueDouble);
                    }
                }
                chartResultValueDetailVO.setUnit(unit);
                // 处理穿透
                String through = chartRuleQueryHelp.getThrough(chartEntity, chartResultPojo);
                chartResultValueDetailVO.setThrough(through);
                break;
            default:
                break;
        }
        //置入单个统计数值
        chartResultValueDetailVO.setValue(total);
        return chartResultValueDetailVO;
    }

    /**
     * 获取自定义指标
     *
     * @param chartEntity     指标 信息
     * @param chartResultPojo 获取指标结果参数pojo
     * @return String
     */
    private String getCustomResultValue(ChartEntity chartEntity, ChartResultPojo chartResultPojo) throws XbbException {
        String resultValue = "";
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword", chartResultPojo.getCorpid()));
        boolQueryBuilder.filter(termQuery("del", DelEnum.NORMAL.getDel()));
        JSONObject driverSources = chartEntity.getDriverSources();
        SlaveSourcePojo driverSourcePojo = driverSources.toJavaObject(SlaveSourcePojo.class);
        Integer businessType = driverSourcePojo.getBusinessType();
        List<ConditionsEntityExt> conditionList = new ArrayList<>();
        saasListDataPermissionHelp.listDataPermission(conditionList, chartResultPojo.getLoginUser(), businessType, businessType);
        if (conditionList.size() > 0) {
            EsUtil.parseCondition(boolQueryBuilder, conditionList, null, chartResultPojo.getCorpid(), businessType);
        }
        JSONArray filterArray = chartEntity.getFilter();
        //如果是自定义客户指标 默认只显示所有客户列表的数据
        // 判断是否是公海客户
        boolean isPublicFlag = false;
        if (Objects.equals(XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), businessType)) {
            isPublicFlag= ChartUtil.isPublicFlag(filterArray);
        } else if (Objects.equals(XbbRefTypeEnum.CLUE.getCode(), businessType)){
            isPublicFlag= ChartUtil.isPublicFlag(filterArray);
        } else if (Objects.equals(XbbRefTypeEnum.CUSTOMER_COMMUNICATE.getCode(), businessType)) {
            boolQueryBuilder.filter(termQuery(FieldTypeEnum.LOG_TYPE.getAlias(), BasicConstant.ZERO));
        }
        //按照人去统计
        JSONObject belongAttr = chartEntity.getBelongAttr();
        String belong = "";
        if (!belongAttr.isEmpty()) {
            FieldAttrEntity belongAttrPojo = belongAttr.toJavaObject(FieldAttrEntity.class);
            belong = belongAttrPojo.getAttr();
        }
        //默认给创建人
        if (StringUtil.isEmpty(belong)) {
            belongAttr.put("attr", FieldTypeEnum.CREATORID.getAlias());
            belongAttr.put("fieldType", FieldTypeEnum.CREATORID.getType());
        }
        JSONObject jsonObject = JSONObject.parseObject(belongAttr.toJSONString());
        jsonObject.put("symbol", ConditionEnum.EQUAL.getSymbol());
        //若为全公司直接抛弃
        // 非目标且非全公司筛选、首页业绩目标且过滤离职人员，则塞入userId条件
        boolean flag = (chartResultPojo.getCheckedDepId() == null || !BasicConstant.ONE.equals(chartResultPojo.getCheckedDepId().intValue())) || (chartResultPojo.getPerformancePk() && !commonHelp.isShowPerformLeave(chartResultPojo.getCorpid()));
        // 用来接收图表原有的filter
        JSONArray tempFilter = null;
        if (flag) {
            if (CollectionsUtil.isNotEmpty(chartResultPojo.getUserIdIn())) {
                if (chartResultPojo.getUserIdIn().size() > 1) {
                    jsonObject.put("symbol", ConditionEnum.IN.getSymbol());
                }
                if (Objects.equals(FieldTypeEnum.USER_GROUP.getType(), belongAttr.getInteger("fieldType"))) {
                    jsonObject.put("symbol", ConditionEnum.IN.getSymbol());
                }
                List<Object> userIdList = new ArrayList<>(chartResultPojo.getUserIdIn());
                jsonObject.put("value", userIdList);
                jsonObject.put("formId", chartEntity.getDriverSources().getInteger("formId"));
                JSONArray jsonArray = new JSONArray();
                jsonArray.add(jsonObject);
                JSONArray filter = chartEntity.getFilter();
                tempFilter = CloneUtil.deepClone4Obj(filter);
                if (filter != null) {
                    filter.add(jsonObject);
                    chartEntity.setFilter(filter);
                } else {
                    chartEntity.setFilter(jsonArray);
                }
            } else {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100018);
            }
        }

        //默认给创建时间
        //按照时间去统计
        JSONObject timeAttr = chartEntity.getTimeAttr();
        String fieldTime = "";
        if (!timeAttr.isEmpty()) {
            FieldAttrEntity timeAttrPojo = timeAttr.toJavaObject(FieldAttrEntity.class);
            fieldTime = customHelp.getAttr(timeAttrPojo);
        }
        if (StringUtil.isEmpty(fieldTime)) {
            fieldTime = FieldTypeEnum.ADDTIME.getAlias();
        }
        IndexTypeEnum indexTypeEnum = indexTypeModel.getIndexType(chartEntity.getCorpid(), driverSourcePojo.getBusinessType(), driverSourcePojo.getSaasMark());
        //时间范围
        Integer startTime = chartResultPojo.getStartTime();
        Integer endTime = chartResultPojo.getEndTime();
        boolQueryBuilder.filter(rangeQuery(fieldTime).gte(startTime).lt(endTime));

        //限定formId
        boolQueryBuilder.filter(termQuery("formId", driverSourcePojo.getFormId()));
        // 跟进记录不需要flowStatus条件，性能问题 by kaka
        if (!IDX_SAAS_CUSTOMER_COMMUNICATE.getCode().equals(indexTypeEnum.getCode())) {
            boolQueryBuilder.filter(termsQuery("flowStatus", Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.PASS.getType())));
        }
        //解析查询条件
        EsUtil.parseConditionIntersection(boolQueryBuilder, chartEntity, isPublicFlag);
        // 把图表原来的filter晒回去，以免出现同一个图表的filter累加问题
        chartEntity.setFilter(tempFilter);
        customHelp.customIndexQueryDefaultFilter(chartEntity, boolQueryBuilder);
        //统计字段
        JSONObject sourceAttrObject = chartEntity.getSourceAttr();
        String source = "";
        if (!sourceAttrObject.isEmpty()) {
            FieldAttrEntity belongAttrPojo = sourceAttrObject.toJavaObject(FieldAttrEntity.class);
            source = customHelp.getAttr(belongAttrPojo);
        }
        if (StringUtil.isEmpty(source)) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224025);
        }
        //设置查询路由
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD,indexTypeEnum.getType()));
        sourceBuilder.query(boolQueryBuilder);
        SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());
        searchRequest.source(sourceBuilder);
        if(Objects.equals(AggTypeEnum.COUNT.getCode(),chartEntity.getStatisticsWay())) {
            CountRequest countRequest = new CountRequest(indexTypeEnum.getIndex());
            countRequest.query(searchRequest.source().query());
            long countLong = xbbElasticsearchRestTemplate.count(countRequest);
            return String.valueOf(countLong);
        }else {
            AggTypeEnum aggTypeEnum = AggTypeEnum.getByCode(chartEntity.getStatisticsWay());
            AggregationBuilder avgAggregationBuilder = null;
                String key = "key";
            switch (aggTypeEnum) {
                case SUM:
                    avgAggregationBuilder = AggregationBuilders.sum(key).field(source);
                    break;
                case AVG:
                    avgAggregationBuilder = AggregationBuilders.avg(key).field(source).missing(0);
                    break;
                case MAX:
                    avgAggregationBuilder = AggregationBuilders.max(key).field(source);
                    break;
                case MIN:
                    avgAggregationBuilder = AggregationBuilders.min(key).field(source);
                    break;
                default:
                    break;
            }
            //聚合条件设置
            sourceBuilder.aggregation(avgAggregationBuilder);
            EsUtil.setPage(sourceBuilder, 0, 0);
            //执行查询，得到结果
            JSONObject responseObject = xbbElasticsearchRestTemplate.getAggResponseJson(searchRequest);
            JSONObject aggregations = responseObject.getJSONObject("aggregations");
            if (!aggregations.isEmpty()) {
                JSONObject hits = responseObject.getJSONObject("hits");
                Integer hit = hits.getInteger("total");
                chartResultPojo.setCount(hit);
                JSONObject tempAggregations = aggregations.getJSONObject(key);
                if (tempAggregations != null && !tempAggregations.isEmpty()) {
                    Object value = tempAggregations.get("value");
                    if (value != null) {
                        resultValue = value.toString();
                    }
                }
            }
        }
        return resultValue;
    }

    /**
     * 获取自定义pk指标，pk榜默认逻辑
     * @param userEntity
     * @param chartEntity
     * @param chartResultPkPojo
     * @return com.xbongbong.pro.statistic.result.pojo.vo.ChartResultPkDetailVO
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2022/3/21 8:46
     * @version 1.0
     */
    private ChartResultPkDetailVO getCustomResultValue4Pk(UserEntity userEntity, ChartEntity chartEntity, ChartResultPkPojo chartResultPkPojo) throws XbbException {
        return getCustomResultValue4Pk(userEntity, chartEntity, chartResultPkPojo, RedisConstant.PK_RULE);
    }

    /**
     * 获取自定义pk指标
     *
     * @param chartEntity     指标 信息
     * @param chartResultPkPojo 获取指标结果参数pojo
     * @return ChartResultPkDetailVO
     */
    private ChartResultPkDetailVO getCustomResultValue4Pk(UserEntity userEntity, ChartEntity chartEntity, ChartResultPkPojo chartResultPkPojo, String redisConstant) throws XbbException {
        // 缓存
        ChartResultRedisPojo chartResultRedisPojo = new ChartResultRedisPojo(chartResultPkPojo, redisConstant);
        String redisKey = systemChartHelp.createSysStatisticsRedisKey(chartResultRedisPojo);
        String redisResult = paasRedisHelper.getValue(RedisPrefixConstant.SYS_STATISTICS, redisKey);
        ChartResultPkDetailVO chartResultPkDetailVO = JsonHelperUtil.parseObject(redisResult, ChartResultPkDetailVO.class);
        if (Objects.nonNull(chartResultPkDetailVO)) {
            customHelp.unitConversion(chartEntity);
            return chartResultPkDetailVO;
        }
        chartResultPkDetailVO = new ChartResultPkDetailVO();
        // 处理参数
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword", chartResultPkPojo.getCorpid()));
        boolQueryBuilder.filter(termQuery("del", DelEnum.NORMAL.getDel()));
        JSONObject driverSources = chartEntity.getDriverSources();
        SlaveSourcePojo driverSourcePojo = driverSources.toJavaObject(SlaveSourcePojo.class);
        Integer businessType = driverSourcePojo.getBusinessType();
        List<ConditionsEntityExt> conditionList = new ArrayList<>();
        // 全部数据 、 全公司top3 + 数据权限   就跳过
        if (Objects.equals(chartEntity.getPowerType(), BasicConstant.ZERO)) {
            saasListDataPermissionHelp.listDataPermission(conditionList, chartResultPkPojo.getLoginUser(), businessType, businessType);
        }
        if (conditionList.size() > 0) {
            EsUtil.parseCondition(boolQueryBuilder, conditionList, null, chartResultPkPojo.getCorpid(), businessType);
        }
        JSONArray filterArray = chartEntity.getFilter() == null ? new JSONArray() : chartEntity.getFilter();
        //如果是自定义客户指标,默认显示公海数据
        boolean isPublicFlag = false;
        if (Objects.equals(XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), businessType)) {
            Iterator<Object> iterator = filterArray.iterator();
            while (iterator.hasNext()) {
                JSONObject filterJson = (JSONObject) iterator.next();
                String saasAttr = filterJson.getString("saasAttr");
                if (Objects.equals(saasAttr, CustomerManagementEnum.IS_PUBLIC.getSaasAttr())) {
                    isPublicFlag = true;
                }
            }
        } else if (Objects.equals(XbbRefTypeEnum.CLUE.getCode(), businessType)){
            Iterator<Object> iterator = filterArray.iterator();
            while (iterator.hasNext()) {
                JSONObject filterJson = (JSONObject) iterator.next();
                String saasAttr = filterJson.getString("saasAttr");
                if (Objects.equals(saasAttr, ClueEnum.IS_PUBLIC.getSaasAttr())) {
                    isPublicFlag = true;
                }
            }
        } else if (Objects.equals(XbbRefTypeEnum.CUSTOMER_COMMUNICATE.getCode(), businessType)) {
            boolQueryBuilder.filter(termQuery(FieldTypeEnum.LOG_TYPE.getAlias(), BasicConstant.ZERO));
        }

        //按照人去统计
        JSONObject belongAttr = chartEntity.getBelongAttr();
        if (belongAttr.isEmpty()) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.NO_BELONG_AMOUNT_DETAIL);
        }
        if (Objects.nonNull(chartResultPkPojo.getUserIdIn())) {
            List<Object> userIdList = new ArrayList<>(chartResultPkPojo.getUserIdIn());
            belongAttr.put(StringConstant.VALUE, userIdList);
            belongAttr.put(StringConstant.FORM_ID, chartEntity.getDriverSources().getInteger(StringConstant.FORM_ID));
            belongAttr.put(StringConstant.SYMBOL, ConditionEnum.IN.getSymbol());
            boolean noSetFlag = true;
            for (int i = 0; i < filterArray.size(); i++) {
                JSONObject filterObj = filterArray.getJSONObject(i);
                // 同样的attr覆盖
                if (Objects.equals(filterObj.getString(StringConstant.SYMBOL), ConditionEnum.IN.getSymbol()) && Objects.equals(filterObj.getString(StringConstant.ATTR), belongAttr.getString(StringConstant.ATTR))) {
                    filterArray.set(i, filterObj);
                    noSetFlag = false;
                    break;
                }
            }
            // 未命中覆盖再添加
            if (noSetFlag) {
                filterArray.add(belongAttr);
            }
            chartEntity.setFilter(filterArray);
        } else {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100018);
        }

        //按照时间去统计，默认给创建时间
        JSONObject timeAttr = chartEntity.getTimeAttr();
        String fieldTime = "";
        if (!timeAttr.isEmpty()) {
            FieldAttrEntity timeAttrPojo = timeAttr.toJavaObject(FieldAttrEntity.class);
            fieldTime = customHelp.getAttr(timeAttrPojo);
        }
        if (StringUtil.isEmpty(fieldTime)) {
            fieldTime = FieldTypeEnum.ADDTIME.getAlias();
        }
        //时间范围
        Integer startTime = chartResultPkPojo.getStartTime();
        Integer endTime = chartResultPkPojo.getEndTime();
        boolQueryBuilder.filter(rangeQuery(fieldTime).gte(startTime).lt(endTime));

        //限定formId
        boolQueryBuilder.filter(termQuery("formId", driverSourcePojo.getFormId()));
        if (!Objects.equals(XbbRefTypeEnum.DISTRIBUTOR_ACCOUNT.getCode(),businessType)
                && !Objects.equals(XbbRefTypeEnum.CUSTOMER_COMMUNICATE.getCode(),businessType)){
            boolQueryBuilder.filter(termsQuery("flowStatus", Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.PASS.getType())));
        }
        //解析查询条件
        EsUtil.parseConditionIntersection(boolQueryBuilder, chartEntity, isPublicFlag);
        customHelp.customIndexQueryDefaultFilter(chartEntity, boolQueryBuilder);
        //统计字段
        JSONObject sourceAttrObject = chartEntity.getSourceAttr();
        String source = "";
        if (!sourceAttrObject.isEmpty()) {
            FieldAttrEntity sourceAttrPojo = sourceAttrObject.toJavaObject(FieldAttrEntity.class);
            source = customHelp.getAttr(sourceAttrPojo);
        }
        if (StringUtil.isEmpty(source)) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224025);
        }
        AggTypeEnum aggTypeEnum = AggTypeEnum.getByCode(chartEntity.getStatisticsWay());
        AggregationBuilder avgAggregationBuilder = null;
        String key = "aggs02";
        switch (aggTypeEnum) {
            case SUM:
                avgAggregationBuilder = AggregationBuilders.sum(key).field(source);
                break;
            case AVG:
                // todo: 有bug就改为sum，然后在内存求平均
                avgAggregationBuilder = AggregationBuilders.avg(key).field(source).missing(0);
                break;
            case MAX:
                avgAggregationBuilder = AggregationBuilders.max(key).field(source);
                break;
            case MIN:
                avgAggregationBuilder = AggregationBuilders.min(key).field(source);
                break;
            case COUNT:
                avgAggregationBuilder = AggregationBuilders.count(key).field("id");
                break;
            default:
                break;
        }
        // 设置查询
        IndexTypeEnum indexTypeEnum = indexTypeModel.getIndexType(chartEntity.getCorpid(), driverSourcePojo.getBusinessType(), driverSourcePojo.getSaasMark());
        String fieldGroup = customHelp.getAttr4Keyword(belongAttr.toJavaObject(FieldAttrEntity.class));
        TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("aggs01").field(fieldGroup);
        termsAggregationBuilder.executionHint(ElasticConstant.EXECUTION_HINT);
        termsAggregationBuilder.subAggregation(avgAggregationBuilder);
        // 执行查询
        int pkType = chartResultPkPojo.getPkType();
        UnitEnum unitEnum = UnitEnum.getByAlias(chartEntity.getUnit());
        unitEnum = unitEnum == null ? UnitEnum.CUSTOM : unitEnum;
        switch (unitEnum) {
            case NUMBER:
                chartResultPkDetailVO = pkRuleHelp.getPkResult4Count(userEntity, chartEntity, chartResultPkPojo, chartResultPkDetailVO, indexTypeEnum, boolQueryBuilder, termsAggregationBuilder, pkType);
                break;
            case MONEY:
                // 类型转换，之后千分位符等格式化会用到
                chartResultPkPojo.setValueTypeEnum(ValueTypeEnum.VALUE_MONEY);
                chartResultPkDetailVO = pkRuleHelp.getPkResult4Double(userEntity, chartEntity, chartResultPkPojo, chartResultPkDetailVO, indexTypeEnum, boolQueryBuilder, termsAggregationBuilder, pkType);
                break;
            case CUSTOM:
                chartResultPkPojo.setValueTypeEnum(ValueTypeEnum.VALUE_DOUBLE);
                chartResultPkDetailVO = pkRuleHelp.getPkResult4Double(userEntity, chartEntity, chartResultPkPojo, chartResultPkDetailVO, indexTypeEnum, boolQueryBuilder, termsAggregationBuilder, pkType);
                break;
            default:
                break;
        }
        //置入缓存
        paasRedisHelper.setValue(RedisPrefixConstant.SYS_STATISTICS, redisKey, chartResultPkDetailVO, RedisTimeConstant.TINY_DURATION);
        customHelp.unitConversion(chartEntity);
        return chartResultPkDetailVO;
    }

    /**
     * 获取业绩目标统计结果（目标值、完成值、完成率）
     *
     * @param indexFlag             当resultFromEnum值为“hamlet”时代表千人千面请求，不在考核范围的不能过滤，而是要返回一个不在考核范围的信息
     * @param companyStructTypeEnum 公司架构类型枚举, 筛选组织架构使用 1员工，2部门
     * @param chartEntity           图表
     * @param systemCodeEnum        系统指标枚举
     * @param chartResultPojo       统计请求参数
     * @param timePojo              穿透时间参数pojo
     * @return com.xbongbong.pro.statistic.pojo.PkPerforInfoPojo
     * @throws XbbException
     * @author zcp
     * @date 2019/3/28 20:22
     * @version v1.0
     * @since v1.0
     */
    private PkPerforInfoPojo getResultPerformance(boolean indexFlag, CompanyStructTypeEnum companyStructTypeEnum, ChartEntity chartEntity, SystemCodeEnum systemCodeEnum, ChartResultPojo chartResultPojo, TimePojo timePojo) throws XbbException {
        PkPerforInfoPojo pkPerforInfoPojo = BeanUtil.copyProperties(chartEntity, PkPerforInfoPojo.class, false);
        pkPerforInfoPojo.setId(String.valueOf(chartEntity.getId()));
        List<IdNamePojo> permissionList = performanceHelp.getPermissionList(chartEntity);
        String corpid = chartResultPojo.getCorpid();
        Long chartId = chartEntity.getId();
        Integer statisticsType = chartEntity.getStatisticsType();
        String unit = customHelp.setUnit(chartEntity);
        ThroughDTO throughDTO = null;
        switch (companyStructTypeEnum) {
            case USER:
                //筛选的员工id
                String checkedUserId = chartResultPojo.getCheckedUserId();
                if (!performanceHelp.checkViewPerformanceSetByUserId(corpid, checkedUserId, permissionList, chartId)) {
                    pkPerforInfoPojo.setMsg(String.format(I18nMessageUtil.getMessage(StringConstant.PERFORMANCE_SET_NOT_IN_PERMISSIONS), I18nMessageUtil.getMessage(CommonConstant.EMPLOYEE), chartEntity.getName()));
                    if (indexFlag) {
                        //首页不在考核范围则标识“不在考核范围”相关标记
                        return pkPerforInfoPojo;
                    } else {
                        //非首页不在考核范围则跳过
                        return null;
                    }
                }
                throughDTO = new ThroughDTO(chartResultPojo, null, checkedUserId, systemCodeEnum);
                break;
            case DEPARTMENT:
                //筛选的部门id
                Long checkedDepId = chartResultPojo.getCheckedDepId();
                if (!performanceHelp.checkViewPerformanceSetByDeptId(corpid, checkedDepId, permissionList, chartId)) {
                    pkPerforInfoPojo.setMsg(String.format(I18nMessageUtil.getMessage(StringConstant.PERFORMANCE_SET_NOT_IN_PERMISSIONS), I18nMessageUtil.getMessage(CommonConstant.DEPARTMENT), chartEntity.getName()));
                    if (indexFlag) {
                        return pkPerforInfoPojo;
                    } else {
                        //非首页不在考核范围则跳过
                        return null;
                    }
                }
                throughDTO = new ThroughDTO(chartResultPojo, checkedDepId, null, systemCodeEnum);
                break;
            default:
                break;
        }

        // 目标值
        Double target = performanceHelp.performanceTarget(companyStructTypeEnum, chartResultPojo, chartEntity);
        boolean bigData = commonHelp.checkBlacklistBigDataCorp(chartEntity.getCorpid());
        Double finish = 0D;
        if (!bigData) {
            // 判断是否是系统目标
            boolean systemFlag = Objects.equals(chartResultPojo.getStatisticsType(), StatisticsTypeEnum.SYSTEM_STATISTIC.getCode());
            Object finishObject = getDepFinish4Total(systemFlag, systemCodeEnum, chartResultPojo);
            String finishString = finishObject.toString();
            finish = StringUtil.toDouble(finishString.replaceAll(",", ""), 0D);
            //置入穿透员工
            if (throughHelp.checkThrough(chartResultPojo, systemCodeEnum)) {
                String through = throughHelp.getThrough(throughDTO, timePojo);
                pkPerforInfoPojo.setThrough(through);
            }
        }
        //置入穿透员工
        if (throughHelp.checkThrough(chartResultPojo, systemCodeEnum)) {
            String through = throughHelp.getThrough(throughDTO, timePojo);
            pkPerforInfoPojo.setThrough(through);
        }

        //属性赋值，分别赋值“完成值”，“目标值”，“完成率”，“未完成值”
        pkPerforInfoPojo.setFinish(StringUtil.formatDouble(finish));
        pkPerforInfoPojo.setTarget(StringUtil.formatDouble(target));
        pkPerforInfoPojo.setRate(String.valueOf(PerformanceUtil.formatRate(target, finish)));
        String unFinish = PerformanceUtil.calculateUnFinish4Target(target, finish);
        pkPerforInfoPojo.setUnFinish(unFinish);

        // 处理数值格式，系统目标金额字段或者自定义目标需要处理
        Integer numFormat = NumFormatEnum.DEFAULT.getCode();
        if (Objects.equals(statisticsType, StatisticsTypeEnum.SYSTEM_STATISTIC.getCode())) {
            // 目前系统目标只对金额字段做处理
            if (Objects.equals(systemCodeEnum.getHasAmount(), 1)) {
                // 系统目标存在最外层大表里
                numFormat = chartResultPojo.getNumFormat();
            }
        } else {
            // 自定义存在对应表里
            numFormat = chartEntity.getNumFormat() == null ? numFormat : chartEntity.getNumFormat();
        }
        if (!Objects.equals(numFormat, NumFormatEnum.DEFAULT.getCode())) {
            NumFormatEnum numFormatEnum = NumFormatEnum.getByCode(numFormat);
            // 单位
            unit = numFormatEnum.getUnit();
            // 完成值
            pkPerforInfoPojo.setFinish(ChartResultUtil.formatVal2Thousands(BigDecimal.valueOf(finish), numFormatEnum));
            // 目标值为-1，前端会回显未设置，未完成值会显示“--”
            if (!Objects.equals(target, -1.0)) {
                pkPerforInfoPojo.setTarget(ChartResultUtil.formatVal2Thousands(BigDecimal.valueOf(target), numFormatEnum));
                pkPerforInfoPojo.setUnFinish(ChartResultUtil.formatVal2Thousands(new BigDecimal(unFinish.replaceAll(",", "")), numFormatEnum));
            }
        }
        // 修改数值后面显示的单位
        pkPerforInfoPojo.setUnit(unit);
        return pkPerforInfoPojo;
    }


    /**
     * 员工呼出/呼入统计
     * 统计范围：三个月内前100名员工的统计记录
     *
     * @param userEntity      登录员工
     * @param chartResultPojo 系统参数pojo
     * @param outOrIn true:呼入，false:呼出
     * @return com.xbongbong.pro.statistic.result.pojo.vo.CallStatisticsVO
     * @throws XbbException
     * @author youli.chen
     * @date: 2019-02-25 16:35
     * @version v1.0
     * @since v1.0
     */
    private CallStatisticsVO callStatistics4User(UserEntity userEntity, ChartResultPojo chartResultPojo, String sortAttr, boolean sortType, boolean outOrIn) throws XbbException {
        // 返回数据：标题数组、表格数据数组、分页信息
        CallStatisticsVO callVO = new CallStatisticsVO();
        // 所有下属（筛选的某个部门的）
        List<String> subUserIdIn = chartResultPojo.getUserIdIn();
        if (subUserIdIn.size() == 0) {
            return callVO;
        }
        String corpid = userEntity.getCorpid();

        /*----------------处理标题----------------*/
        List<TitlePojo> title = new ArrayList<>();
        title.add(new TitlePojo("serialNum", I18nMessageUtil.getMessage(I18nStringConstant.SERIAL_NUM), BasicConstant.ZERO, BasicConstant.ONE));
        title.add(new TitlePojo("name", I18nMessageUtil.getMessage(I18nStringConstant.STAFF), BasicConstant.ZERO, BasicConstant.ZERO));
        title.add(new TitlePojo("depName", I18nMessageUtil.getMessage(I18nStringConstant.DEPARTMENT), BasicConstant.ZERO, BasicConstant.ZERO));
        if(outOrIn){
            title.add(new TitlePojo("callInNum", I18nMessageUtil.getMessage(I18nStringConstant.CALL_IN_NUM), BasicConstant.ONE, BasicConstant.ONE));
            title.add(new TitlePojo("callInSuccessNum", I18nMessageUtil.getMessage(I18nStringConstant.CALL_IN_SUCCESS_NUM), BasicConstant.ONE, BasicConstant.ONE));
            title.add(new TitlePojo("callInSuccessRate", I18nMessageUtil.getMessage(I18nStringConstant.CALL_IN_SUCCESS_RATE), BasicConstant.ONE, BasicConstant.ONE));
            title.add(new TitlePojo("callInTime", I18nMessageUtil.getMessage(I18nStringConstant.CALL_IN_TIME), BasicConstant.ONE, BasicConstant.ONE));
            title.add(new TitlePojo("callInAverageTime", I18nMessageUtil.getMessage(I18nStringConstant.CALL_IN_AVERAGE_TIME), BasicConstant.ONE, BasicConstant.ONE));
        } else {
            title.add(new TitlePojo("callOutNum", I18nMessageUtil.getMessage(I18nStringConstant.CALL_OUT_NUM), BasicConstant.ONE, BasicConstant.ONE));
            title.add(new TitlePojo("callOutSuccessNum", I18nMessageUtil.getMessage(I18nStringConstant.CALL_OUT_SUCCESS_NUM), BasicConstant.ONE, BasicConstant.ONE));
            title.add(new TitlePojo("callOutSuccessRate", I18nMessageUtil.getMessage(I18nStringConstant.CALL_OUT_SUCCESS_RATE), BasicConstant.ONE, BasicConstant.ONE));
            title.add(new TitlePojo("callOutTime", I18nMessageUtil.getMessage(I18nStringConstant.CALL_OUT_TIME), BasicConstant.ONE, BasicConstant.ONE));
            title.add(new TitlePojo("callOutAverageTime", I18nMessageUtil.getMessage(I18nStringConstant.CALL_OUT_AVERAGE_TIME), BasicConstant.ONE, BasicConstant.ONE));
        }

        /*--------处理查询条件--------*/
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.boolQueryBuilder4LimitStart(chartResultPojo, "callTime");
        boolQueryBuilder.filter(termsQuery("userId.keyword", subUserIdIn));
        if(outOrIn){
            boolQueryBuilder.filter(rangeQuery("type").gte(BasicConstant.ZERO).lte(BasicConstant.ZERO));
        } else {
            boolQueryBuilder.filter(rangeQuery("type").gte(BasicConstant.ONE).lte(BasicConstant.ONE));
        }
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_CALL_CENTER_CALL_LOG.getType()));
        Integer code = CallCenterCallLogCallSourceEnum.CALL_CENTER.getCode();
        boolQueryBuilder.filter(rangeQuery("callSource").gte(code).lte(code));

        // 默认按照呼叫时间进行排序，涉及到时间大小，可以按照通话时长排序
        String logAttr;
        if(Objects.equals(sortAttr, "callInTime") || Objects.equals(sortAttr, "callOutTime")){
            logAttr = "duration";
        } else {
            logAttr = "callTime";
        }

        // 分组聚合计算，直接取100条
        List<String> sumFieldList = Arrays.asList("callTime", "duration");
        List<CallLogAggsPojo> result = crmCallLogResult.sumMuchCallAttr4Sort(IndexTypeEnum.IDX_CALL_CENTER_CALL_LOG, boolQueryBuilder, sumFieldList, logAttr, sortType);
        // 存放所有userIds
        Set<String> permissionUserIdIn = new HashSet<>();
        result.forEach(callLogAggsPojo -> permissionUserIdIn.add(callLogAggsPojo.getUserId()));

        // 获取成功呼叫次数
        boolQueryBuilder.filter(rangeQuery("result").gte(BasicConstant.ONE).lte(BasicConstant.ONE));
        List<CallLogAggsPojo> successNumResult = crmCallLogResult.sumMuchCallAttr4Sort(IndexTypeEnum.IDX_CALL_CENTER_CALL_LOG, boolQueryBuilder, sumFieldList, logAttr, sortType);
        Map<String, Double> successNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        successNumResult.forEach(callLogAggsPojo -> successNumMap.put(callLogAggsPojo.getUserId(), callLogAggsPojo.getCallCount()));

        // 如果对呼叫成功数进行排序，重新调整result集合位置
        if(Objects.equals(sortAttr, "callInSuccessNum") || Objects.equals(sortAttr, "callOutSuccessNum")){
            List<CallLogAggsPojo> successAggsList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            result.forEach(callLogAggsPojo -> {
                String userId = callLogAggsPojo.getUserId();
                if(successNumMap.get(userId) != null || (result.size() > successNumResult.size())){
                    successAggsList.add(callLogAggsPojo);
                }
            });
            result.clear();
            result.addAll(successAggsList);
        }

        // 百分数排序准备
        for(CallLogAggsPojo aggsPojo : result){
            String uid = aggsPojo.getUserId();
            // 呼叫次数
            Double callCount = aggsPojo.getCallCount();
            // 总计时长
            Double durationCount = aggsPojo.getDurationCount();
            // 成功次数
            Double successCallCount = successNumMap.get(uid) == null ? BasicConstant.ZERO_DOUBLE : successNumMap.get(uid);
            // 呼叫成功率
            Double rate = (callCount == 0) ? 0 : Arith.div(successCallCount, callCount) * 100;
            if (rate > 0) {
                rate = StringUtil.toDouble(StringUtil.formatDouble(rate, 2, 1));
            } else {
                rate = 0.00;
            }
            // 平均呼叫时长
            Double avgTime = (successCallCount == 0) ? 0 : Arith.div(durationCount, successCallCount);
            if (avgTime > 0) {
                avgTime = StringUtil.toDouble(StringUtil.formatDouble(avgTime, 2, 1));
            } else {
                avgTime = 0.00;
            }
            aggsPojo.setRate(rate);
            aggsPojo.setAvgTime(avgTime);
        }

        // 如果对呼叫成功率进行排序，重新调整result集合位置
        if(Objects.equals(sortAttr, "callInSuccessRate") || Objects.equals(sortAttr, "callOutSuccessRate")){
            if(sortType){
                // asc升序
                // lambda无法处理double类型排序
                // result.stream().sorted(Comparator.comparing(CallLogAggsPojo::getRate)).collect(Collectors.toList());
                Collections.sort(result, new Comparator<CallLogAggsPojo>() {
                    @Override
                    public int compare(CallLogAggsPojo o1, CallLogAggsPojo o2) {
                        return o1.getRate().compareTo(o2.getRate());
                    }
                });
            } else {
                // desc倒序
                // result.stream().sorted(Comparator.comparing(CallLogAggsPojo::getRate).reversed()).collect(Collectors.toList());
                Collections.sort(result, new Comparator<CallLogAggsPojo>() {
                    @Override
                    public int compare(CallLogAggsPojo o1, CallLogAggsPojo o2) {
                        return o2.getRate().compareTo(o1.getRate());
                    }
                });
            }
        }
        // 如果对平均呼叫时长进行排序，重新调整result集合位置
        if(Objects.equals(sortAttr, "callInAverageTime") || Objects.equals(sortAttr, "callOutAverageTime")){
            if(sortType){
                // asc升序
                // result.stream().sorted(Comparator.comparing(CallLogAggsPojo::getAvgTime)).collect(Collectors.toList());
                Collections.sort(result, new Comparator<CallLogAggsPojo>() {
                    @Override
                    public int compare(CallLogAggsPojo o1, CallLogAggsPojo o2) {
                        return o1.getAvgTime().compareTo(o2.getAvgTime());
                    }
                });
            } else {
                // desc倒序
                // result.stream().sorted(Comparator.comparing(CallLogAggsPojo::getAvgTime).reversed()).collect(Collectors.toList());
                Collections.sort(result, new Comparator<CallLogAggsPojo>() {
                    @Override
                    public int compare(CallLogAggsPojo o1, CallLogAggsPojo o2) {
                        return o2.getAvgTime().compareTo(o1.getAvgTime());
                    }
                });
            }
        }

        // 拓展使用 使用成功率进行降序排序，次数相同再使用时长升序排序
        /*result.stream()
                .sorted(Comparator.comparing(CallLogAggsPojo::getRate).reversed().thenComparing(CallLogAggsPojo::getCallCount))
                .collect(Collectors.toList());*/

        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("columns", "user_id,name,department,del");
        param.put("corpid", corpid);
        // 包含离职员工、且包含隐藏员工
        param.put("userIdIn", permissionUserIdIn);

        PageHelper pageHelper = PageHelperUtil.getPageHelper(param, userModel, chartResultPojo.getPageSize());
        List<UserEntity> userList = userModel.findEntitys(param);

        // 离职人员
        Map<String, UserEntity> leaveUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        // 人员
        Map<String, String> userMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        userList.forEach(item -> {
            String userId = item.getUserId();
            if(item.getDel().equals(1)){
                leaveUserMap.put(userId, item);
            }
            userMap.put(userId, item.getName());
        });

        // userId--员工所在部门名称合集
        Map<String, String> nameUserDepsMap = departmentModel.formatUserDepNames(corpid, userList);
        // 表格数据封装
        JSONArray dataArray = new JSONArray();
        int i = 0;
        for(CallLogAggsPojo aggsPojo : result){
            i++;
            String uid = aggsPojo.getUserId();
            String uName = userMap.get(uid);
            if (leaveUserMap.get(uid) != null && leaveUserMap.get(uid).getDel().equals(1)) {
                uName = uName + "(" + I18nMessageUtil.getMessage(CommonConstant.LEAVE) + ")";
            }
            // 呼叫次数
            Double callCount = aggsPojo.getCallCount();
            // 总计时长
            Double durationCount = aggsPojo.getDurationCount();
            // 成功次数
            Double successCallCount = successNumMap.get(uid) == null ? BasicConstant.ZERO_DOUBLE : successNumMap.get(uid);
            // 呼叫成功率
            Double rate = aggsPojo.getRate();
            String num = rate + "%";
            // 平均呼叫时长
            Double avgTime = aggsPojo.getAvgTime();

            JSONObject jsonObject = new JSONObject();
            jsonObject.put("id", uid);
            jsonObject.put("serialNum", i);
            jsonObject.put("name", uName);
            jsonObject.put("depName", nameUserDepsMap.get(uid));

            BigDecimal duration = BigDecimal.valueOf(durationCount);
            String callTimeStr = DateTimeUtil.secondToTime(duration.intValue());
            BigDecimal avg = BigDecimal.valueOf(avgTime);
            String avgTimeStr = DateTimeUtil.secondToTime(avg.intValue());
            if(outOrIn){
                jsonObject.put("callInNum", callCount);
                jsonObject.put("callInSuccessNum", successCallCount);
                jsonObject.put("callInSuccessRate", num);
                jsonObject.put("callInTime", callTimeStr);
                jsonObject.put("callInAverageTime", avgTimeStr);
            } else {
                jsonObject.put("callOutNum", callCount);
                jsonObject.put("callOutSuccessNum", successCallCount);
                jsonObject.put("callOutSuccessRate", num);
                jsonObject.put("callOutTime", callTimeStr);
                jsonObject.put("callOutAverageTime", avgTimeStr);
            }
            dataArray.add(jsonObject);
        }
        // 返回数据：标题数组、表格数据数组、分页信息
        callVO.setTitle(title);
        callVO.setPageHelper(pageHelper);
        callVO.setData(dataArray);
        return callVO;
    }

    /**
     * 员工呼出/呼入统计总计
     * 统计范围：三个月内的所有统计记录
     *
     * @param userEntity      登录员工
     * @param chartResultPojo 系统参数pojo
     * @param outOrIn true:呼入，false:呼出
     * @return com.xbongbong.pro.statistic.result.pojo.vo.CallStatisticsVO
     * @throws XbbException
     * @author youli.chen
     * @date: 2019-02-25 16:35
     * @version v1.0
     * @since v1.0
     */
    private CallStatisticsVO callStatistics4UserTotal(UserEntity userEntity, ChartResultPojo chartResultPojo, boolean outOrIn) throws XbbException {
        // 返回数据：标题数组、表格数据数组、分页信息
        CallStatisticsVO callVO = new CallStatisticsVO();
        // 所有下属（筛选的某个部门的）
        List<String> subUserIdIn = chartResultPojo.getUserIdIn();
        if (subUserIdIn.size() == 0) {
            return callVO;
        }

        /*--------处理查询条件--------*/
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.boolQueryBuilder4LimitStart(chartResultPojo, "callTime");
        boolQueryBuilder.filter(termsQuery("userId.keyword", subUserIdIn));
        if(outOrIn){
            boolQueryBuilder.filter(rangeQuery("type").gte(BasicConstant.ZERO).lte(BasicConstant.ZERO));
        } else {
            boolQueryBuilder.filter(rangeQuery("type").gte(BasicConstant.ONE).lte(BasicConstant.ONE));
        }

        // 聚合计算
        List<String> sumFieldList = Arrays.asList("duration");
        CallLogAggsPojo result = crmCallLogResult.sumMuchCallAttr4Total(IndexTypeEnum.IDX_CALL_CENTER_CALL_LOG, boolQueryBuilder, sumFieldList);

        ElasticAggsPojo elasticAggsPojo = systemChartHelp.distinctAggregations(chartResultPojo, ValueTypeEnum.VALUE_TYPE, IndexTypeEnum.IDX_CALL_CENTER_CALL_LOG, boolQueryBuilder, "callTime", "userId.keyword");
        Double countUser = elasticAggsPojo.getTotal() == null ? BasicConstant.ZERO_DOUBLE : Double.valueOf(elasticAggsPojo.getTotal());

        // 获取成功呼叫次数
        boolQueryBuilder.filter(rangeQuery("result").gte(BasicConstant.ONE).lte(BasicConstant.ONE));
        CallLogAggsPojo successNumResult = crmCallLogResult.sumMuchCallAttr4Total(IndexTypeEnum.IDX_CALL_CENTER_CALL_LOG, boolQueryBuilder, sumFieldList);

        // 呼叫次数
        Double callCount = result.getCallCount();
        Double avgCallCount = (countUser == 0) ? 0 : Arith.div(callCount, countUser);
        if (avgCallCount > 0) {
            avgCallCount = StringUtil.toDouble(StringUtil.formatDouble(avgCallCount, 2, 1));
        } else {
            avgCallCount = 0.00;
        }

        // 总计时长
        Double durationCount = result.getDurationCount();
        Double avgDurationCount = (countUser == 0) ? 0 : Arith.div(durationCount, countUser);
        if (avgDurationCount > 0) {
            avgDurationCount = StringUtil.toDouble(StringUtil.formatDouble(avgDurationCount, 2, 1));
        } else {
            avgDurationCount = 0.00;
        }

        // 成功次数
        Double successCallCount = successNumResult.getCallCount();
        Double avgSuccessCallCount = (countUser == 0) ? 0 : Arith.div(successCallCount, countUser);
        if (avgSuccessCallCount > 0) {
            avgSuccessCallCount = StringUtil.toDouble(StringUtil.formatDouble(avgSuccessCallCount, 2, 1));
        } else {
            avgSuccessCallCount = 0.00;
        }

        // 呼叫成功率
        Double rate = (callCount == 0) ? 0 : Arith.div(successCallCount, callCount) * 100;
        if (rate > 0) {
            rate = StringUtil.toDouble(StringUtil.formatDouble(rate, 2, 1));
        } else {
            rate = 0.00;
        }
        String num = rate + "%";

        // 平均呼叫时长
        Double avgTime = (successCallCount == 0 ) ? 0 : Arith.div(durationCount, successCallCount);
        if (avgTime > 0) {
            avgTime = StringUtil.toDouble(StringUtil.formatDouble(avgTime, 2, 1));
        } else {
            avgTime = 0.00;
        }

        // 表格数据封装
        JSONArray dataArray = new JSONArray();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("average", I18nMessageUtil.getMessage(I18nStringConstant.CALL_AVERAGE));

        BigDecimal duration = BigDecimal.valueOf(avgDurationCount);
        String avgDurationCountStr = DateTimeUtil.secondToTime(duration.longValue());
        BigDecimal avg = BigDecimal.valueOf(avgTime);
        String avgTimeStr = DateTimeUtil.secondToTime(avg.longValue());
        if(outOrIn){
            jsonObject.put("callInNum", avgCallCount);
            jsonObject.put("callInSuccessNum", avgSuccessCallCount);
            jsonObject.put("callInSuccessRate", num);
            jsonObject.put("callInTime", avgDurationCountStr);
            jsonObject.put("callInAverageTime", avgTimeStr);
        } else {
            jsonObject.put("callOutNum", avgCallCount);
            jsonObject.put("callOutSuccessNum", avgSuccessCallCount);
            jsonObject.put("callOutSuccessRate", num);
            jsonObject.put("callOutTime", avgDurationCountStr);
            jsonObject.put("callOutAverageTime", avgTimeStr);
        }
        dataArray.add(jsonObject);
        // 返回数据：标题数组、表格数据数组、分页信息
        callVO.setData(dataArray);
        return callVO;
    }

    /**
     * 员工目标完成情况：
     * 所有员工的所有指标（在考核对象内）的完成情况
     *
     * @param userEntity      登录员工
     * @param chartResultPojo 系统参数pojo
     * @return com.xbongbong.pro.statistic.result.pojo.vo.PerformanceFinishVO
     * @throws XbbException
     * @author hongxiao
     * @date: 2019-02-25 16:35
     * @version v1.0
     * @update 2019-4-1 从main-service移入 by zcp
     * @since v1.0
     */
    private PerformanceFinishVO performanceFinish4User(UserEntity userEntity, ChartResultPojo chartResultPojo) throws XbbException {
        // TODO: 2019/4/1 该方法肯定超过80行，后期考虑抽方法
        // 返回数据：标题数组、表格数据数组、分页信息
        PerformanceFinishVO finishVO = new PerformanceFinishVO();
        // 所有下属（筛选的某个部门的）
        List<String> subUserIdIn = chartResultPojo.getUserIdIn();
        if (subUserIdIn.size() == 0) {
            return finishVO;
        }
        String corpid = userEntity.getCorpid();
        FiscalYearTimePojo fiscalYearTimePojo = chartResultPojo.getFiscalYearTimePojo();
        TimeTypeEnum timeTypeEnum = fiscalYearTimePojo.getTimeTypeEnum4DefaultMonth();
        boolean systemFlag = Objects.equals(chartResultPojo.getStatisticsType(), StatisticsTypeEnum.SYSTEM_STATISTIC.getCode());
        // 获取登录员工能看到的指标列表：登录员工没有在任何考核指标内，则返回空
        List<ChartEntity> setList;
        if (systemFlag) {
            setList = performanceHelp.getViewList(userEntity);
        } else {
            setList = performanceHelp.getViewList4Customer(userEntity, chartResultPojo);
        }
        if (setList.size() == 0) {
            return finishVO;
        }
        int startMonth = fiscalYearTimePojo.getStartMonth();
        Integer startTime = chartResultPojo.getStartTime();
        Integer endTime = chartResultPojo.getEndTime();
        // 处理财年年份：处理一些当前时间跨财年的情况
        Integer fiscalYear = FiscalYearHelp.dealWithFiscalYear(timeTypeEnum, fiscalYearTimePojo, startTime, endTime);
        //财年起始时间戳
        Integer fiscalStartTime = FiscalYearHelp.getFiscalYearStartInt(fiscalYear, startMonth);
        // 每周工作日天数
        Double workingDayWeek = companyConfigModel.getWorkingDayWeek(corpid);
        // 每月工作日天数
        Double workingDayMonth = companyConfigModel.getWorkingDayMonth(corpid);
        // 存放所有的考核对象userIds
        Set<String> permissionUserIdIn = new HashSet<>();
        // 指标id--该指标的考核userIds
        Map<Long, Set<String>> permissionUserIdsMap = new HashMap<>(setList.size());
        // 固定数值型的指标id--固定目标
        Map<Long, Double> fixedValueMap = new HashMap<>(setList.size());
        // 所有启用的变化数值型的指标ids
        Set<Long> changeSetIdIn = new HashSet<>();
        changeSetIdIn.add(-1L);
        // 显示的指标列表
        List<ChartEntity> showList = new ArrayList<>();
        // 指标id--该指标所有考核对象的完成情况
        Map<Long, Map<String, PkInfoPojo>> finishMap = new HashMap<>(setList.size());
        /*----------------处理标题----------------*/
        List<TitlePojo> title = new ArrayList<>();
        title.add(new TitlePojo("name", I18nMessageUtil.getMessage(I18nStringConstant.NAME)));
        title.add(new TitlePojo("depName", I18nMessageUtil.getMessage(CommonConstant.DEPARTMENT)));
        // 处理是否显示离职人员
        boolean enable = commonHelp.isShowPerformLeave(corpid);
        // 设置返回值
        for (ChartEntity setEntity : setList) {
            SystemCodeEnum systemCodeEnum = SystemCodeEnum.getByCode(setEntity.getSystemCode());
            Integer statisticsType = setEntity.getStatisticsType();
            Long setId = setEntity.getId();
            List<IdNamePojo> permissionList = performanceHelp.getPermissionList(setEntity);
            // 从缓存读考核对象
            Set<String> uidInSet = performanceHelp.getPermission2UserIdInFromJedis(corpid, permissionList, setId);

            //与下属取交集，不为空则获取其完成情况：所有下属都不在考核对象内，则无需该目标
            uidInSet.retainAll(subUserIdIn);
            uidInSet.remove("-1");
            if (uidInSet.size() == 0) {
                continue;
            }
            permissionUserIdIn.addAll(uidInSet);
            showList.add(setEntity);
            permissionUserIdsMap.put(setId, uidInSet);
            // 考核方式：1动态数值型,2固定数值型
            PerformanceSetExplainPojo explainPojo = performanceHelp.getPerformanceSetExplainPojo(setEntity);
            Integer assessType = explainPojo.getAssessType();
            if (assessType == AssessTypeEnum.FIXED.getCode()) {
                // 处理固定目标
                double value = PerformanceHelp.getFixedData(setEntity, timeTypeEnum, workingDayWeek, workingDayMonth, startTime, endTime);
                fixedValueMap.put(setId, value);
            } else {
                changeSetIdIn.add(setId);
            }
            // 封装标题其他参数
            String key = "id_" + setId;
            String value = setEntity.getName() + I18nMessageUtil.getMessage(I18nStringConstant.GOAL_COMPLETION);
            String unit = customHelp.setUnit(setEntity);
            // 数值格式单位处理
            unit = handleUnit4NumFormat(chartResultPojo, setEntity, systemCodeEnum, statisticsType, unit);
            if (!StringUtil.isEmpty(unit)) {
                value += "/" + I18nMessageUtil.getMessage(CommonConstant.UNIT) + "：" + unit;
            }
            TitlePojo titleChart = new TitlePojo(key, value);
            List<TitlePojo> child = new ArrayList<>();
            child.add(new TitlePojo("target_" + key, I18nMessageUtil.getMessage(CommonConstant.TARGET_VALUE)));
            child.add(new TitlePojo("finish_" + key, I18nMessageUtil.getMessage(CommonConstant.COMPLETION_VALUE), null, BasicConstant.ONE));
            child.add(new TitlePojo("rate_" + key, I18nMessageUtil.getMessage(CommonConstant.COMPLETION_RATE), null, BasicConstant.ONE));
            titleChart.setChild(child);
            title.add(titleChart);
        }
        /*----------------判断与下属取过交集后是否还有员工ids：所有下属都不在考核对象内，则无需处理目标----------------*/
        if (permissionUserIdIn.size() == 0) {
            return finishVO;
        }
        Map<String, Object> param = new HashMap<>(16);
        param.put("columns", "user_id,name,department,del");
        param.put("corpid", corpid);
        // 包含离职员工、且包含隐藏员工
        param.put("userIdIn", permissionUserIdIn);
        param.put("page", chartResultPojo.getPage());
        // 过滤离职员工
        if (!enable) {
            param.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        }

        PageHelper pageHelper = PageHelperUtil.getPageHelper(param, userModel, chartResultPojo.getPageSize());
        List<UserEntity> userList = (List<UserEntity>) PageHelperUtil.getEntityList(param, pageHelper, userModel);
        /*----------------当页员工ids----------------*/
        Set<String> uidIn = new HashSet<>();
        uidIn.add("-1");
        for (UserEntity entity : userList) {
            uidIn.add(entity.getUserId());
        }
        /*
          （1）只计算当前页员工的完成值
          （2）并处理穿透链接：穿透入相应业务，且拼上员工信息、标题信息
         */
        // 把pojo内的userIdIn置为当页员工ids
        chartResultPojo.setUserIdIn(new ArrayList<>(uidIn));
        ChartResultPkPojo chartResultPkPojo = BeanUtil.copyProperties(chartResultPojo, ChartResultPkPojo.class, false);
        // 处理离职人员
        chartResultPkPojo.setPkLeave(enable);
        for (ChartEntity setEntity : showList) {
            // 获取finish
            ChartResultPkDetailVO chartResultPkDetailVO = getChartResultPkDetailVO(userEntity, systemFlag, chartResultPkPojo, setEntity);
            finishMap.put(setEntity.getId(), formatPkInfoPojo2Json(chartResultPkDetailVO.getPkData()));
        }
        // userId--员工所在部门名称合集
        Map<String, String> nameUserDepsMap = departmentModel.formatUserDepNames(corpid, userList);
        /*----------------查询变化数值类型的员工的目标----------------*/
        param.clear();
        param.put("corpid", corpid);
        param.put("del", DelEnum.NORMAL.getDel());
        param.put("userIdIn", uidIn);
        param.put("setIdIn", changeSetIdIn);
        param.put("objectiveType", CompanyStructTypeEnum.USER.getCode());
        param.put("year", fiscalYear);
        List<PerformanceEntity> list = (List<PerformanceEntity>) BasicHelper.findEntitysByImitatePage(param, performanceModel);
        /*
          封装员工的各个目标
          key：“userId_setId”
          value：目标对象
         */
        Map<String, PerformanceEntity> userPerformanceMap = new HashMap<>(list.size());
        for (PerformanceEntity entity : list) {
            String key = entity.getUserId() + "_" + entity.getSetId();
            userPerformanceMap.put(key, entity);
        }
        //封装数据
        JSONArray dataArray = new JSONArray();
        for (UserEntity entity : userList) {
            String uid = entity.getUserId();
            String uName = entity.getName();
            if (entity.getDel().equals(1)) {
                uName = uName + "(" + I18nMessageUtil.getMessage(CommonConstant.LEAVE) + ")";
            }
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("id", uid);
            jsonObject.put("name", uName);
            jsonObject.put("depName", nameUserDepsMap.get(uid));
            // 该员工的各个目标--可能不在某个指标的考核对象内，需要判断
            for (ChartEntity setEntity : showList) {
                Long setId = setEntity.getId();
                String keyTarget = "target_id_" + setId;
                String keyFinish = "finish_id_" + setId;
                String keyRate = "rate_id_" + setId;
                // target默认值为-1（如果设置了，在置为相应值）
                Double target = -1D, finish = 0D;
                // 先判断该员工是否在该指标的考核范围内
                Set<String> uidSet = permissionUserIdsMap.get(setId);
                if (!uidSet.contains(uid)) {
                    // fix:修改不在考核范围内的员工的目标值设置为“未设置”，完成值为“--”，完成率为“--”，并跳出循环处理下一个指标
                    Double rate = -1D;
                    jsonObject.put(keyTarget, target);
                    jsonObject.put(keyFinish, StringConstant.DOUBLE_LINE);
                    jsonObject.put(keyRate, rate);
                    continue;
                }
                // 不管设置还是未设置，都计算完成值
                Map<String, PkInfoPojo> userPkInfoMap = finishMap.get(setId);
                PkInfoPojo pkInfoPojo = userPkInfoMap.getOrDefault(uid, new PkInfoPojo());
                String value = pkInfoPojo.getValue();
                if (!StringUtil.isEmpty(value)) {
                    finish = StringUtil.toDouble(value.replace(",", ""), 0D);
                }
                // 穿透链接
                String throughKey = "through_" + keyFinish;
                jsonObject.put(throughKey, pkInfoPojo.getThrough());
                PerformanceSetExplainPojo explainPojo = performanceHelp.getPerformanceSetExplainPojo(setEntity);
                if (explainPojo.getAssessType() == AssessTypeEnum.FIXED.getCode()) {
                    // 处理固定数值型目标
                    target = fixedValueMap.get(setId);
                } else {
                    PerformanceEntity performanceEntity = userPerformanceMap.get(uid + "_" + setId);
                    if (performanceEntity != null) {
                        // 如果设置了目标，才处理
                        JSONObject targetObject = performanceEntity.getTarget();
                        if (targetObject.size() > 0) {
                            // 获取业绩目标（根据时间筛选进行乘除运算，求出相应维度目标）
                            target = PerformanceHelp.getChangeData(targetObject, setEntity, timeTypeEnum,
                                    fiscalYearTimePojo, workingDayWeek, workingDayMonth, fiscalStartTime);
                        }
                    }
                }
                jsonObject.put(keyTarget, PerformanceUtil.formatTarget(target));
                jsonObject.put(keyFinish, StringUtil.formatDouble(finish));
                jsonObject.put(keyRate, PerformanceUtil.formatRate(target, finish));
                // 处理数值格式
                handleNumFormat4Performance(chartResultPojo, jsonObject, setEntity, keyTarget, keyFinish, target, finish);
            }
            dataArray.add(jsonObject);
        }
        // 返回数据：标题数组、表格数据数组、分页信息
        finishVO.setTitle(title);
        finishVO.setPageHelper(pageHelper);
        finishVO.setData(dataArray);
        return finishVO;
    }

    /**
     * 部门完成情况：
     * 选择的部门及其下一级子部门的指标（在考核对象内）完成情况
     *
     * @param userEntity      登录员工
     * @param chartResultPojo 系统参数pojo
     * @return com.xbongbong.pro.statistic.result.pojo.vo.PerformanceFinishVO
     * @throws XbbException
     * @author hongxiao
     * @date: 2019-02-25 16:36
     * @version v1.0
     * @update 2019-4-1 从main-service移入 by zcp
     * @since v1.0
     */
    private PerformanceFinishVO performanceFinish4Dep(UserEntity userEntity, ChartResultPojo chartResultPojo) throws XbbException {
        // TODO: 2019/4/1 该方法肯定超过80行，后期考虑抽方法
        String corpid = userEntity.getCorpid();
        Long departmentId = chartResultPojo.getCheckedDepId();
        DepartmentEntity entity = departmentModel.getByKey(departmentId, corpid);
        if (departmentId == null || entity == null) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240006, PerformanceErrorCodeEnum.API_ERROR_240006.getMsg(), I18nMessageUtil.getMessage(CommonConstant.DEPARTMENT));
        }
        FiscalYearTimePojo fiscalYearTimePojo = chartResultPojo.getFiscalYearTimePojo();
        TimeTypeEnum timeTypeEnum = fiscalYearTimePojo.getTimeTypeEnum4DefaultMonth();
        boolean systemFlag = Objects.equals(chartResultPojo.getStatisticsType(), StatisticsTypeEnum.SYSTEM_STATISTIC.getCode());
        // 获取登录员工能看到的指标列表
        List<ChartEntity> setList;
        if (systemFlag) {
            setList = performanceHelp.getViewList(userEntity);
        } else {
            setList = performanceHelp.getViewList4Customer(userEntity, chartResultPojo);
        }
        // 返回数据：标题数组、表格数据数组、分页信息
        PerformanceFinishVO finishVO = new PerformanceFinishVO();
        if (setList.size() == 0) {
            return finishVO;
        }
        // 所有下属（筛选的某个部门的）
        List<String> subUserIdIn = chartResultPojo.getUserIdIn();
        int datePermission = chartResultPojo.getDataPermission();
        Set<Long> subDepIdIn = new HashSet<>();
        // 判断登录员工是否有主管部门：看list是否有值
        if (datePermission != DataPermissionEnum.ALL.getCode()) {
            // 获取自己主管的部门
            subDepIdIn.addAll(userModel.getUserManageDeptIdList(userEntity, true));
            // 获取主管的部门的子部门
            subDepIdIn.addAll(departmentModel.getSubDepIdList(corpid, subDepIdIn));
            if (subUserIdIn.size() == 0 || subDepIdIn.size() == 0) {
                return finishVO;
            }
        }
        /*
         * 筛选一个部门后，获取该部门、及该部门下一级的子部门
         * 是否是自己主管部门：取交集，看是否为空
         */
        List<DepartmentEntity> subDepartmentList = departmentModel.getSubOneLevel(corpid, departmentId);
        // 把选择的部门也先塞入进来，为了获取其所属员工ids
        subDepartmentList.add(entity);
        // 选中的部门及其下一级部门ids
        Set<Long> subOneLevelIdList = new HashSet<>();
        for (DepartmentEntity departmentEntity : subDepartmentList) {
            Long depId = departmentEntity.getId();
            subOneLevelIdList.add(depId);
        }
        if (datePermission != DataPermissionEnum.ALL.getCode()) {
            // 选中的部门（及一级子部门）与自己所管理的部门取交集
            subOneLevelIdList.retainAll(subDepIdIn);
        }
        if (subOneLevelIdList.size() == 0) {
            // 选中的部门都不是自己主管的部门
            return finishVO;
        }
        int startMonth = fiscalYearTimePojo.getStartMonth();
        fiscalYearTimePojo.setStartMonth(startMonth);
        Integer startTime = chartResultPojo.getStartTime();
        Integer endTime = chartResultPojo.getEndTime();
        // 处理财年年份：处理一些当前时间跨财年的情况
        Integer fiscalYear = FiscalYearHelp.dealWithFiscalYear(timeTypeEnum, fiscalYearTimePojo, startTime, endTime);
        // 财年起始时间戳
        Integer fiscalStartTime = FiscalYearHelp.getFiscalYearStartInt(fiscalYear, startMonth);
        // 每周工作日天数
        Double workingDayWeek = companyConfigModel.getWorkingDayWeek(corpid);
        // 每月工作日天数
        Double workingDayMonth = companyConfigModel.getWorkingDayMonth(corpid);

        // 存放所有的考核对象部门ids
        Set<Long> permissionDepIdIn = new HashSet<>();
        // 指标id--该指标的考核部门ids
        Map<Long, List<Long>> permissionDepIdsMap = new HashMap<>(setList.size());
        // 固定数值型的指标id--固定目标
        Map<Long, Double> fixedValueMap = new HashMap<>(setList.size());
        // 所有启用的变化数值型的指标ids
        Set<Long> changeSetIdIn = new HashSet<>();
        changeSetIdIn.add(-1L);
        // 显示的指标列表
        List<ChartEntity> showList = new ArrayList<>();
        //图表id---图表对应的穿透dto
        Map<Long, ThroughDTO> throughDtoMap = new HashMap<>(setList.size());
        // key--部门完成额，其中key=“depId_setId”
        Map<String, Double> finishDepMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        /*----------------判断筛选的部门（及下一级子部门）是否是所有指标的考核对象，并处理标题、固定目标等----------------*/
        List<TitlePojo> title = new ArrayList<>();
        title.add(new TitlePojo("depName", I18nMessageUtil.getMessage(CommonConstant.DEPARTMENT)));
        // 处理是否显示离职人员
        boolean enable = commonHelp.isShowPerformLeave(corpid);
        Integer viewPermission = enable ? BasicConstant.ONE : BasicConstant.ZERO;
        for (ChartEntity setEntity : setList) {
            SystemCodeEnum systemCodeEnum = SystemCodeEnum.getByCode(setEntity.getSystemCode());
            Integer statisticsType = setEntity.getStatisticsType();
            // 从缓存读考核对象
            Long setId = setEntity.getId();
            List<IdNamePojo> permissionList = performanceHelp.getPermissionList(setEntity);
            List<Long> depIdSet = performanceHelp.getPermission2DepIdInFromJedis(corpid, setId, permissionList);
            /*
              与选择的部门（及其下一级子部门）取交集，不为空则获取其完成情况
              注：此时的subOneLevelIdList已经与下属做过交集
             */
            depIdSet.retainAll(subOneLevelIdList);
            depIdSet.remove(-1L);
            if (depIdSet.size() == 0) {
                // 所有部门都不在该指标的考核对象内，则无需该目标
                continue;
            }
            permissionDepIdIn.addAll(depIdSet);
            showList.add(setEntity);
            permissionDepIdsMap.put(setId, depIdSet);
            // 考核方式：1动态数值型,2固定数值型
            PerformanceSetExplainPojo explainPojo = performanceHelp.getPerformanceSetExplainPojo(setEntity);
            if (explainPojo.getAssessType() == AssessTypeEnum.FIXED.getCode()) {
                // 处理固定目标
                double value = PerformanceHelp.getFixedData(setEntity, timeTypeEnum, workingDayWeek, workingDayMonth, startTime, endTime);
                fixedValueMap.put(setId, value);
            } else {
                changeSetIdIn.add(setId);
            }
            String key = "id_" + setId;
            String value = setEntity.getName() + I18nMessageUtil.getMessage(I18nStringConstant.GOAL_COMPLETION);
            String unit = customHelp.setUnit(setEntity);
            // 数值格式单位处理
            unit = handleUnit4NumFormat(chartResultPojo, setEntity, systemCodeEnum, statisticsType, unit);
            // 拼接标题
            if (!StringUtil.isEmpty(unit)) {
                value += "/" + I18nMessageUtil.getMessage(CommonConstant.UNIT) + "：" + unit;
            }
            TitlePojo titleChart = new TitlePojo(key, value);
            List<TitlePojo> child = new ArrayList<>();
            child.add(new TitlePojo("target_" + key, I18nMessageUtil.getMessage(CommonConstant.TARGET_VALUE)));
            child.add(new TitlePojo("finish_" + key, I18nMessageUtil.getMessage(CommonConstant.COMPLETION_VALUE), null, BasicConstant.ONE));
            child.add(new TitlePojo("rate_" + key, I18nMessageUtil.getMessage(CommonConstant.COMPLETION_RATE), null, BasicConstant.ONE));
            titleChart.setChild(child);
            title.add(titleChart);
            ThroughDTO throughDTO = new ThroughDTO(systemCodeEnum);
            throughDtoMap.put(setId, throughDTO);
        }
        if (permissionDepIdIn.size() == 0) {
            return finishVO;
        }
        // 先把筛选的顶级部门的id移去--单独查询后，塞入顶部
        permissionDepIdIn.remove(departmentId);
        permissionDepIdIn.add(-1L);
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("columns", "id,name");
        param.put("corpid", corpid);
        param.put("del", 0);
        param.put("idIn", permissionDepIdIn);
        param.put("page", chartResultPojo.getPage());
        PageHelper pageHelper = PageHelperUtil.getPageHelper(param, departmentModel, chartResultPojo.getPageSize());
        List<DepartmentEntity> departmentList = (List<DepartmentEntity>) PageHelperUtil.getEntityList(param, pageHelper, departmentModel);
        // 当页部门ids
        Set<Long> didIn = new HashSet<>();
        /*
          把选中的那个上级部门塞入进去--让其恒在顶部，这样做达到两个目的：
          （1）设计稿上，第一个选中的部门，是恒在第一行的，下面的行是其下一层子级部门
          （2）第一个为顶级，那它所包含的员工肯定是大于等于子级部门包含的员工ids，因此第一次算完成额时计算的缓存是所有
         */
        departmentList.add(0, entity);
        // 处理当前页各个部门，各个指标的完成情况
        // 部门id--该部门下的所有员工ids（包含子部门，且与下属取交集）
        Map<Long, Set<String>> depUserIdsMap = new HashMap<>(departmentList.size());
        for (DepartmentEntity department : departmentList) {
            Long depId = department.getId();
            didIn.add(depId);
            // 处理该部门的员工，1包含离职员工
            List<Long> depIdIn = new ArrayList<>();
            depIdIn.add(depId);
            List<String> uidInList = userModel.getUserIdsRecursionDep(depIdIn, corpid, viewPermission);
            Set<String> uidInSet = new HashSet<>(uidInList);
            // 与下属取交集
            uidInSet.retainAll(subUserIdIn);
            if (uidInSet.size() == 0) {
                continue;
            }
            depUserIdsMap.put(depId, uidInSet);
            // 计算完成额
            chartResultPojo.setUserIdIn(new ArrayList<>(uidInSet));
            chartResultPojo.setCheckedDepId(depId);
            // 该部门的各个目标--可能不在某个指标的考核对象内，需要判断
            for (ChartEntity setEntity : showList) {
                Long setId = setEntity.getId();
                List<Long> permissionDepIds = permissionDepIdsMap.get(setId);
                if (permissionDepIds == null || !permissionDepIds.contains(depId)) {
                    // 该部门不在该指标的考核对象内
                    continue;
                }
                ThroughDTO throughDTO = throughDtoMap.get(setId);
                SystemCodeEnum systemCodeEnum = throughDTO.getSystemCodeEnum();
                chartResultPojo.setChartEntity(setEntity);
                Object object = getDepFinish4Total(systemFlag, systemCodeEnum, chartResultPojo);
                //把获取到的带","的值替换为""
                String finishStr = object.toString();
                String finishReplace = finishStr.replace(",", "");
                Double finish = StringUtil.toDouble(finishReplace);
                finishDepMap.put(depId + "_" + setId, finish);
            }
        }
        /*
         * 查询变化数值类型的部门的目标
         */
        param.clear();
        param.put("corpid", corpid);
        param.put("del", 0);
        param.put("depIdIn", didIn);
        param.put("setIdIn", changeSetIdIn);
        param.put("objectiveType", CompanyStructTypeEnum.DEPARTMENT.getCode());
        param.put("year", fiscalYear);
        List<PerformanceEntity> list = (List<PerformanceEntity>) BasicHelper.findEntitysByImitatePage(param, performanceModel);
        /*
          封装部门的各个目标
          key：“depId_setId”
          value：目标对象
         */
        Map<String, PerformanceEntity> depPerformanceMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (PerformanceEntity performanceEntity : list) {
            String key = performanceEntity.getDepartmentId() + "_" + performanceEntity.getSetId();
            depPerformanceMap.put(key, performanceEntity);
        }
        // 封装最后结果
        JSONArray dataArray = new JSONArray();
        CompanyStructTypeEnum companyStructTypeEnum = CompanyStructTypeEnum.DEPARTMENT;
        //穿透需要参数
        TimePojo timePojo = throughHelp.formatThroughTimeInfo(false, fiscalYearTimePojo, startTime, endTime);
        for (DepartmentEntity department : departmentList) {
            Long depId = department.getId();
            String depName = department.getName();
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("id", depId);
            jsonObject.put("depName", depName);
            // 该部门的员工ids（已经与下属取过交集）
            Set<String> uidInSet = depUserIdsMap.get(depId);
            // 该部门的各个目标--可能不在某个指标的考核对象内，需要判断
            for (ChartEntity setEntity : showList) {
                Long setId = setEntity.getId();
                String keyTarget = "target_id_" + setId;
                String keyFinish = "finish_id_" + setId;
                String keyRate = "rate_id_" + setId;
                Double target = -1D, finish;
                // 先判断该员工是否在该指标的考核范围内
                List<Long> permissionDepIds = permissionDepIdsMap.get(setId);
                if (permissionDepIds == null || !permissionDepIds.contains(depId)) {
                    // fix:修改不在考核范围内的部门的目标值设置为“未设置”，完成值为“--”，完成率为“--”，并跳出循环处理下一个指标
                    Double rate = -1D;
                    jsonObject.put(keyTarget, target);
                    jsonObject.put(keyFinish, StringConstant.DOUBLE_LINE);
                    jsonObject.put(keyRate, rate);
                    continue;
                }
                String key = depId + "_" + setId;
                // 不管设置还是未设置，都计算完成值
                finish = finishDepMap.get(key);
                finish = finish == null ? Double.valueOf(0D) : finish;
                // 未设置该目标，-1则说明该业绩目标未设置
                jsonObject.put(keyFinish, StringUtil.formatDouble(finish));
                // 穿透链接
                String throughKey = "through_" + keyFinish;
                // 拼上穿透的部门参数、标题
                ThroughDTO throughDTO = throughDtoMap.get(setId);
                chartResultPojo.setChartEntity(setEntity);
                ThroughDTO throughDto = new ThroughDTO(chartResultPojo, depId, null, throughDTO.getSystemCodeEnum());
                String targetThrough = throughHelp.getThrough(throughDto, timePojo);
                jsonObject.put(throughKey, targetThrough);
                // 考核方式：1动态数值型,2固定数值型
                PerformanceSetExplainPojo explainPojo = performanceHelp.getPerformanceSetExplainPojo(setEntity);
                if (explainPojo.getAssessType() == AssessTypeEnum.FIXED.getCode()) {
                    // 得到指标处设置的每个人的固定目标值
                    target = fixedValueMap.get(setId);
                    // 得到该部门的目标值
                    target = performanceHelp.getFixedData4Dep(corpid, target, companyStructTypeEnum, uidInSet);
                } else {
                    PerformanceEntity performanceEntity = depPerformanceMap.get(key);
                    // 设置了目标才进行处理
                    if (performanceEntity != null) {
                        JSONObject targetObject = performanceEntity.getTarget();
                        if (targetObject.size() > 0) {
                            // 获取业绩目标（根据时间筛选进行乘除运算，求出相应维度目标）
                            target = PerformanceHelp.getChangeData(targetObject, setEntity, timeTypeEnum,
                                    fiscalYearTimePojo, workingDayWeek, workingDayMonth, fiscalStartTime);
                        }
                    }
                }
                jsonObject.put(keyTarget, PerformanceUtil.formatTarget(target));
                jsonObject.put(keyFinish, StringUtil.formatDouble(finish));
                jsonObject.put(keyRate, PerformanceUtil.formatRate(target, finish));
                // 处理数值格式
                handleNumFormat4Performance(chartResultPojo, jsonObject, setEntity, keyTarget, keyFinish, target, finish);
            }
            dataArray.add(jsonObject);
        }
        // 返回数据：标题数组、表格数据数组、分页信息
        finishVO.setTitle(title);
        finishVO.setPageHelper(pageHelper);
        finishVO.setData(dataArray);
        return finishVO;
    }

    /**
     * 业绩目标获取finish
     * @param userEntity
     * @param systemFlag 系统or自定义
     * @param chartResultPkPojo
     * @param setEntity
     * @return com.xbongbong.pro.statistic.result.pojo.vo.ChartResultPkDetailVO
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2022/3/18 16:54
     * @version 1.0
     */
    private ChartResultPkDetailVO getChartResultPkDetailVO(UserEntity userEntity, boolean systemFlag, ChartResultPkPojo chartResultPkPojo, ChartEntity setEntity) throws XbbException {
        ChartResultPkDetailVO chartResultPkDetailVO;
        if (systemFlag) {
            SystemCodeEnum systemCodeEnum = SystemCodeEnum.getByCode(setEntity.getSystemCode());
            //把系统枚举systemCodeEnum置入chartResultPojo
            chartResultPkPojo.setSystemCodeEnum(systemCodeEnum);
            setEntity.setPkParams();
            chartResultPkPojo.setChartEntity(setEntity);
            // 计算完成额--并处理穿透链接：穿透入相应业务，且拼上员工信息、标题信息
            chartResultPkDetailVO = (ChartResultPkDetailVO) chartResult.getResult4PkRule(userEntity, setEntity, systemCodeEnum.getXbbRefTypeEnum(), chartResultPkPojo);
        } else {
            chartResultPkPojo.setChartEntity(setEntity);
            // 处理threadLocal
            SlaveSourcePojo driverSourcePojo = JSON.toJavaObject(setEntity.getDriverSources(), SlaveSourcePojo.class);
            TransmittableThreadLocalUtil.setValue(driverSourcePojo.getSaasMark(), driverSourcePojo.getBusinessType(), driverSourcePojo.getMenuId(), chartResultPkPojo.getDistributorMark());
            // 计算完成额
            chartResultPkDetailVO = getCustomResultValue4Pk(userEntity, setEntity, chartResultPkPojo, RedisConstant.PERFORMANCE);
        }
        return chartResultPkDetailVO;
    }

    /**
     * 员工目标完成情况：目标完成情况详情穿透（人员完成率排行），所有员工的所有指标（在考核对象内）的完成情况
     *
     * @param userEntity      登录员工
     * @param chartResultPojo 统计请求参数pojo
     * @param chartEntity     图表实体
     * @return java.util.List<com.xbongbong.pro.statistic.result.pojo.PkPerforInfoPojo>
     * @throws XbbException
     * @author zcp
     * @date 2019/4/4 13:54
     * @version v1.0
     * @since v1.0
     */
    private List<PkPerforInfoPojo> performancePk(UserEntity userEntity, ChartResultPojo chartResultPojo, ChartEntity chartEntity) throws XbbException {
        chartResultPojo.setChartEntity(chartEntity);
        List<PkPerforInfoPojo> pkPerforInfoPojoList = new ArrayList<>();
        boolean systemFlag = Objects.equals(chartEntity.getStatisticsType(), StatisticsTypeEnum.SYSTEM_STATISTIC.getCode());
        // 该部门所有下属员工Id
        List<String> subUserIdIn = chartResultPojo.getUserIdIn();
        subUserIdIn.remove("-1");
        if (subUserIdIn.size() == 0) {
            return pkPerforInfoPojoList;
        }
        FiscalYearTimePojo fiscalYearTimePojo = chartResultPojo.getFiscalYearTimePojo();
        TimeTypeEnum timeTypeEnum = fiscalYearTimePojo.getTimeTypeEnum4DefaultMonth();
        String corpid = userEntity.getCorpid();
        int startMonth = fiscalYearTimePojo.getStartMonth();
        Integer startTime = chartResultPojo.getStartTime();
        Integer endTime = chartResultPojo.getEndTime();
        Integer fiscalYear = FiscalYearHelp.dealWithFiscalYear(timeTypeEnum, fiscalYearTimePojo, startTime, endTime);
        Integer fiscalStartTime = FiscalYearHelp.getFiscalYearStartInt(fiscalYear, startMonth);
        Double workingDayWeek = companyConfigModel.getWorkingDayWeek(corpid);
        Double workingDayMonth = companyConfigModel.getWorkingDayMonth(corpid);
        Long setId = chartEntity.getId();
        List<IdNamePojo> permissionList = performanceHelp.getPermissionList(chartEntity);
        // 从缓存读取指标的考核对象：与下属取交集，生成uidInSet为最终获取的员工集合：判断与下属取过交集后是否还有员工ids
        Set<String> uidInSet = performanceHelp.getPermission2UserIdInFromJedis(corpid, permissionList, setId);
        uidInSet.retainAll(subUserIdIn);
        if (uidInSet.size() == 0) {
            return pkPerforInfoPojoList;
        }
        // 防空处理
        uidInSet.add("-1");
        // 若取完交集后的员工ID存在，则获取完成值
        ChartResultPkPojo chartResultPkPojo = BeanUtil.copyProperties(chartResultPojo, ChartResultPkPojo.class, false);
        SystemCodeEnum systemCodeEnum = SystemCodeEnum.getByCode(chartEntity.getSystemCode());
        //把系统枚举systemCodeEnum置入chartResultPkPojo
        chartResultPkPojo.setSystemCodeEnum(systemCodeEnum);
        // 获取离职人员展示设置
        boolean pkLeave = commonHelp.isShowPerformLeave(corpid);
        chartResultPkPojo.setPkLeave(pkLeave);
        // 封装每个图表对应的回参
        ChartResultPkDetailVO chartResultPkDetailVO = getChartResultPkDetailVO(userEntity, systemFlag, chartResultPkPojo, chartEntity);
        //员工id---员工完成额信息
        Map<String, PkInfoPojo> userPkInfoMap = formatPkInfoPojo2Json(chartResultPkDetailVO.getPkData());
        // 查询要在页面展示的userList
        Map<String, Object> userParam = new HashMap<>(5);
        userParam.put("columns", "user_id,name,department");
        userParam.put("corpid", corpid);
        userParam.put("userIdIn", uidInSet);
        // 离职员工显隐
        if (!pkLeave) {
            userParam.put("del", DelEnum.NORMAL.getDel());
        }
        List<UserEntity> userList = (List<UserEntity>) BasicHelper.findEntitysByImitatePage(userParam, userModel);
        // 考核方式：1动态数值型,2固定数值型
        PerformanceSetExplainPojo explainPojo = performanceHelp.getPerformanceSetExplainPojo(chartEntity);
        Integer assessType = explainPojo.getAssessType();
        // 声明固定数值
        Double fixedValue = null;
        // new一个变化数值uerId--performanceEntity的map
        Map<String, PerformanceEntity> userPerformanceMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (assessType == AssessTypeEnum.FIXED.getCode()) {
            // 处理固定目标
            fixedValue = PerformanceHelp.getFixedData(chartEntity, timeTypeEnum, workingDayWeek, workingDayMonth, startTime, endTime);
        } else {
            // 查询变化数值类型的员工的目标实体列表
            Map<String, Object> performanceParam = new HashMap<>(8);
            performanceParam.put("corpid", corpid);
            performanceParam.put("del", 0);
            performanceParam.put("userIdIn", uidInSet);
            performanceParam.put("setId", setId);
            performanceParam.put("objectiveType", CompanyStructTypeEnum.USER.getCode());
            performanceParam.put("year", fiscalYear);
            List<PerformanceEntity> performanceEntityList = (List<PerformanceEntity>) BasicHelper.findEntitysByImitatePage(performanceParam, performanceModel);
            // 封装员工的目标，key：“userId”；value：目标对象
            for (PerformanceEntity entity : performanceEntityList) {
                String key = entity.getUserId();
                userPerformanceMap.put(key, entity);
            }
        }
        // 处理完成率排名
        Map<String, Object> targetMap = new HashMap<>(userList.size());
        Map<String, Object> finishValueMap = new HashMap<>(userList.size());
        Map<String, Double> rateMap = new HashMap<>(userList.size());
        Map<String, String> rateStrMap = new HashMap<>(userList.size());
        Map<String, String> nameMap = new HashMap<>(userList.size());
        Map<String, String> avatarMap = new HashMap<>(userList.size());
        Map<String, String> nameUserDepsMap = departmentModel.formatUserDepNames(corpid, userList);
        // 遍历员工列表
        for (UserEntity entity : userList) {
            String uid = entity.getUserId();
            nameMap.put(uid, entity.getName());
            avatarMap.put(uid, entity.getAvatar());
            Double target = -1D, finish = -1D;
            // 处理目标值
            // 考核方式：1动态数值型,2固定数值型
            if (assessType == AssessTypeEnum.FIXED.getCode()) {
                // 处理固定目标
                target = fixedValue;
            } else {
                PerformanceEntity performanceEntity = userPerformanceMap.get(uid);
                if (performanceEntity != null && performanceEntity.getTarget().size() > 0) {
                    // 获取业绩目标
                    target = PerformanceHelp.getChangeData(performanceEntity.getTarget(), chartEntity, timeTypeEnum,
                            fiscalYearTimePojo, workingDayWeek, workingDayMonth, fiscalStartTime);
                }
            }
            PkInfoPojo pkInfoPojo = userPkInfoMap.getOrDefault(uid, new PkInfoPojo());
            String value = pkInfoPojo.getValue();
            if (StringUtil.isEmpty(value)) {
                finish = 0D;
            } else {
                finish = StringUtil.toDouble(value.replace(",", ""), 0D);
            }
            // 设置了目标，则计算该指标、该员工的完成值
            targetMap.put(uid, PerformanceUtil.formatTarget(target));
            rateMap.put(uid, PerformanceUtil.formatRate2Double(target, finish));
            rateStrMap.put(uid, Objects.toString(PerformanceUtil.formatRate(target, finish), ""));
            finishValueMap.put(uid, StringUtil.formatDouble(finish));
        }
        //在nameMap中的离职人员名字后面添加"(离职)"
        Set<String> userIds = nameMap.keySet();
        Map<String, Object> param = new HashMap<>();
        param.put("userIdIn",userIds);
        param.put(ParameterConstant.COLUMNS, "user_id, name");
        param.put("corpid", corpid);
        param.put(ParameterConstant.LEAVE_MARKS,BasicConstant.ONE);
        userList = userModel.findEntitys(param);
        nameMap.clear();
        for (UserEntity entity : userList) {
            nameMap.put(entity.getUserId(), entity.getName());
        }

        //处理穿透
        TimePojo timePojo = throughHelp.formatThroughTimeInfo(false, chartResultPkPojo.getFiscalYearTimePojo(), chartResultPkPojo.getStartTime(), chartResultPkPojo.getEndTime());
        Map<String, Integer> rankMap = (Map<String, Integer>) SortHelp.sortMapValueDouble(rateMap, SortHelp.KEY_STRING);
        for (Map.Entry<String, Integer> entry : rankMap.entrySet()) {
            String userId = entry.getKey();
            PkPerforInfoPojo pkPerforInfoPojo = new PkPerforInfoPojo();
            pkPerforInfoPojo.setId(userId);
            pkPerforInfoPojo.setName(nameMap.get(userId)); //根据userId获取对应的name
            pkPerforInfoPojo.setAvatar(avatarMap.get(userId));
            pkPerforInfoPojo.setDepName(nameUserDepsMap.get(userId));
            pkPerforInfoPojo.setTarget(targetMap.get(userId).toString());
            pkPerforInfoPojo.setFinish(finishValueMap.get(userId).toString());
            pkPerforInfoPojo.setRate(rateStrMap.get(userId));
            pkPerforInfoPojo.setRank(entry.getValue());
            //置入穿透员工
            chartResultPkPojo.setCheckedUserId(userId);
            if (throughHelp.checkThrough(chartResultPojo, systemCodeEnum)) {
                //强制单选
                chartResultPkPojo.setSingleCheck(true);
                ThroughDTO throughDTO = new ThroughDTO(chartResultPkPojo, null, userId, systemCodeEnum);
                String through = throughHelp.getThrough(throughDTO, timePojo);
                pkPerforInfoPojo.setThrough(through);
            }
            pkPerforInfoPojoList.add(pkPerforInfoPojo);
        }
        return pkPerforInfoPojoList;
    }

    /**
     * 格式化pk返回数据，封装为JSONObject，key为部门或员工id，value为完成值
     *
     * @param pkInfoPojoList pk内各个员工/部门信息
     * @return java.util.Map<java.lang.String                               ,                               com.xbongbong.pro.statistic.result.pojo.PkInfoPojo>
     * @author zcp
     * @date 2019/4/2 13:44
     * @version v1.0
     * @since v1.0
     */
    private Map<String, PkInfoPojo> formatPkInfoPojo2Json(List<PkInfoPojo> pkInfoPojoList) {
        if(CollectionsUtil.isEmpty(pkInfoPojoList)){
            return new HashMap<>();
        }
        //员工id--员工完成额信息
        Map<String, PkInfoPojo> userPkInfoMap = new HashMap<>(pkInfoPojoList.size());
        for (PkInfoPojo pkInfoPojo : pkInfoPojoList) {
            userPkInfoMap.put(pkInfoPojo.getId(), pkInfoPojo);
        }
        return userPkInfoMap;
    }

    /**
     * 最终要获取目标和完成额的目标
     *
     * @param checkChartIdPojo      图表id，当为null时，则代表web完成情况的详情也是展示仪表盘汇总
     * @param viewList              登录员工查看到的目标list
     * @param chartResultPkDetailVO 返回vo
     * @return java.util.List<com.xbongbong.pro.domain.entity.ChartEntity>
     * @throws XbbException
     * @author zcp
     * @date 2019/4/4 15:00
     * @version v1.0
     * @since v1.0
     */
    private List<ChartEntity> getPerformanceList(ChartIdPojo checkChartIdPojo, List<ChartEntity> viewList, ChartResultPkDetailVO chartResultPkDetailVO) throws XbbException {
        if (Objects.isNull(checkChartIdPojo)) {
            checkChartIdPojo = new ChartIdPojo();
        }
        String from = checkChartIdPojo.getFrom();
        Long checkChartId = checkChartIdPojo.getId();
        //移动端目标完成情况是仪表盘汇总、web完成情况的详情也是展示仪表盘汇总
        boolean allFlag = Objects.isNull(checkChartId)
                || (Objects.equals(StatisticsTypeEnum.SYSTEM_STATISTIC.getCode(), checkChartIdPojo.getStatisticsType()) && (ResultFromEnum.CENTER_WEB.getValue().equals(from) || ResultFromEnum.CENTER_APP.getValue().equals(from)));
        List<ChartEntity> list = new ArrayList<>();
        //true未选择目标，false选择目标
        boolean flag = true;
        for (ChartEntity chartEntity : viewList) {
            Long chartId = chartEntity.getId();
            if (allFlag) {
                //说明为移动端（或web完成情况详情页），要获取所有目标
                flag = false;
                //图表的其他参数（结果值以外）
                BeanUtil.copyProperties(chartEntity, chartResultPkDetailVO);
                list.add(chartEntity);
            } else if (chartId.equals(checkChartId)) {
                //只获取某个目标的结果，其他都清除
                list.clear();
                list.add(chartEntity);
                flag = false;
                //图表的其他参数（结果值以外）
                BeanUtil.copyProperties(chartEntity, chartResultPkDetailVO);
                break;
            } else {
                list.add(chartEntity);
            }
        }
        if (flag) {
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224020, StatisticsServicesErrorCodeEnum.API_ERROR_224020.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.TARGET));
        }
        return list;
    }

    /**
     * 把统计结果置入reportTargetMap
     *
     * @param reportTypeEnum  日报、月报
     * @param chartResultPojo 系统指标请求参数pojo
     * @param reportTargetMap 封装返回结果map：key 为指标alias，@see ReportTargetEnum枚举的alias；value 为统计出的该指标的总额，格式为{“day”:0,”month”:0}
     * @return com.xbongbong.pro.targetlog.pojo.ReportTargetPojo
     * @throws XbbException
     * @author zcp
     * @date 2019/4/16 14:08
     * @version v1.0
     * @since v1.0
     */
    private boolean getSalesReport(ReportTypeEnum reportTypeEnum, ChartResultPojo chartResultPojo, Map<String, JSONObject> reportTargetMap) throws XbbException {
        /**
         需要计算统计结果的简报系统指标枚举list
         */
        List<SystemCodeEnum> systemCodeEnumList = SystemCodeEnum.getList4SalesReport();
        /**
         获取统计结果：
         key为系统指标枚举
         value为该系统指标统计出的总额
         */
        Map<SystemCodeEnum, String> systemResultMap = chartResult.getResult4SystemValue(systemCodeEnumList, chartResultPojo);
        //是否为空，默认空，只要统计有值该值不为空
        boolean emptyFlag = true;
        for (Map.Entry<SystemCodeEnum, String> entry : systemResultMap.entrySet()) {
            SystemCodeEnum systemCodeEnum = entry.getKey();
            ReportTargetEnum reportTargetEnum = ReportTargetEnum.getBySystemCodeEnum(systemCodeEnum);
            if (reportTargetEnum == null) {
                continue;
            }
            String key;
            if (reportTypeEnum == ReportTypeEnum.MONTH) {
                key = "month";
            } else if (reportTypeEnum == ReportTypeEnum.DAY) {
                key = "day";
            } else {
                continue;
            }
            String alias = reportTargetEnum.getAlias();
            JSONObject targetObject = reportTargetMap.get(alias);
            if (targetObject == null) {
                targetObject = new JSONObject();
            }
            String value = entry.getValue();
            if (StringUtil.isNotEmpty(value)) {
                value = value.replaceAll(",", "");
            }
            if (reportTargetEnum.getType() == 1) {
                Double valueDouble = StringUtil.toDouble(value, 0D);
                if (emptyFlag && valueDouble > 0) {
                    //只要一个有值，就置为false，非空
                    emptyFlag = false;
                }
                targetObject.put(key, valueDouble);
            } else {
                Integer valueInteger = StringUtil.toInt(value, 0);
                if (emptyFlag && valueInteger > 0) {
                    emptyFlag = false;
                }
                targetObject.put(key, valueInteger);
            }
            reportTargetMap.put(alias, targetObject);
        }
        return emptyFlag;
    }

    /**
     * 聚合条件组装
     *
     * @param chartEntity 图表实体类
     * @author zhouwq
     * @date 2019/4/10 19:07
     */
    private void chartAggregationsBuilder(ChartEntity chartEntity, SearchSourceBuilder sourceBuilder, Map<String, String> sortMap) throws XbbException {
        Boolean isSingle = EsUtil.getSingle(chartEntity);
        boolean isYearChain = EsUtil.isYearChain(chartEntity);
        FieldAttrPojo classifyAttr = JSONArray.parseArray(chartEntity.getChartClassify().toJSONString(), FieldAttrPojo.class).get(0);
        FieldAttrPojo valueAttr = JSONArray.parseArray(chartEntity.getChartValue().toJSONString(), FieldAttrPojo.class).get(0);
        List<FieldAttrPojo> valueAttrList = JSONArray.parseArray(chartEntity.getChartValue().toJSONString(), FieldAttrPojo.class);
        List<FieldAttrPojo> valueAttrSecondList = null;
        if (CollectionUtils.isNotEmpty(chartEntity.getChartValueSecond())){
            valueAttrSecondList = JSONArray.parseArray(chartEntity.getChartValueSecond().toJSONString(), FieldAttrPojo.class);
        }

        ValuesSourceAggregationBuilder aggResult;
        Boolean classifyAsc = EsUtil.getSortFlag(sortMap, classifyAttr.getAttr() + "&" + classifyAttr.getFieldType());
        if (EsHelper.isDateTimeByFieldType(classifyAttr.getFieldType())) {
            aggResult = esHelper.getBiDateHistogramAggregation(ChartAggNameEnum.AGG_FIRST.getStr(), chartAttrAssemble(classifyAttr, isSingle), classifyAttr.getDateGroupType(), classifyAsc, isYearChain);
        } else if (EsHelper.isTeamLogicByFieldType(classifyAttr.getFieldType(), classifyAttr.getBusinessType())) {
            if (!isSingle) {
                String teamAttr = "myTeamMain_" + EsUtil.getTeamIdx(chartEntity, classifyAttr.getFormId()) + ".userId.keyword";
                TermsAggregationBuilder terms = AggregationBuilders.terms(ChartAggNameEnum.AGG_FIRST.getStr()).field(teamAttr);
                terms.executionHint(ElasticConstant.EXECUTION_HINT);
                aggResult = terms.size(ChartConstant.CHART_AGG_SIZE);
            } else {
                // 特殊索引：这里只是拿了下index的type，所以无需更改
                String teamType = IndexTypeEnum.getChildByParent(classifyAttr.getBusinessType()).getType();
                ChildrenAggregationBuilder childrenAgg = JoinAggregationBuilders.children(ChartAggNameEnum.AGG_FIRST.getStr(), teamType);
                TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms(ChartAggNameEnum.AGG_FIRST.getStr()).field("userId.keyword");
                termsAggregationBuilder.executionHint(ElasticConstant.EXECUTION_HINT);
                aggResult = childrenAgg.subAggregation(termsAggregationBuilder.size(ChartConstant.CHART_AGG_SIZE));
            }
        } else {
            TermsAggregationBuilder builder = AggregationBuilders.terms(ChartAggNameEnum.AGG_FIRST.getStr()).field(chartAttrAssemble(classifyAttr, isSingle)).size(ChartConstant.CHART_AGG_SIZE);
            builder.executionHint(ElasticConstant.EXECUTION_HINT);
            if (classifyAsc != null) {
                builder.order(BucketOrder.key(classifyAsc));
            }
            aggResult = builder;
        }
        AggTypeEnum aggTypeEnum = AggTypeEnum.getByAlias(valueAttr.getAggType());
        Map<FieldAttrPojo,AggTypeEnum> fieldAttrEntityAggTypeEnumMap = new LinkedHashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<FieldAttrPojo,AggTypeEnum> fieldAttrEntityAggTypeEnumSecondMap = new LinkedHashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
//        if (Objects.nonNull(valueAttr)){
//            fieldAttrEntityAggTypeEnumMap.put(valueAttr,aggTypeEnum);
//        }
//        if (Objects.nonNull(valueAttrSecond)){
//            fieldAttrEntityAggTypeEnumMap.put(valueAttrSecond,aggTypeEnumSecond);
//        }
        if (CollectionUtils.isNotEmpty(valueAttrList)){
            valueAttrList.forEach(item ->{
                fieldAttrEntityAggTypeEnumMap.put(item,AggTypeEnum.getByAlias(item.getAggType()));
            });

        }
        if (CollectionUtils.isNotEmpty(valueAttrSecondList)){
            valueAttrSecondList.forEach(item ->{
                fieldAttrEntityAggTypeEnumSecondMap.put(item,AggTypeEnum.getByAlias(item.getAggType()));
            });
        }
        //系列为空则为二级聚合 不为空则为三级聚合
        if (!chartEntity.getChartSeries().isEmpty()) {
            FieldAttrPojo seriesAttr = JSONArray.parseArray(chartEntity.getChartSeries().toJSONString(), FieldAttrPojo.class).get(0);
            ValuesSourceAggregationBuilder sonAggregation;
            Boolean seriesAsc = EsUtil.getSortFlag(sortMap, seriesAttr.getAttr() + "&" + seriesAttr.getFieldType());
            if (EsHelper.isDateTimeByFieldType(seriesAttr.getFieldType())) {
                sonAggregation = esHelper.getBiDateHistogramAggregation(ChartAggNameEnum.AGG_SECOND.getStr(), chartAttrAssemble(seriesAttr, isSingle), seriesAttr.getDateGroupType(), seriesAsc, isYearChain);
            } else if (EsHelper.isTeamLogicByFieldType(seriesAttr.getFieldType(), seriesAttr.getBusinessType())) {
                if (!isSingle) {
                    String teamAttr = "myTeamMain_" + EsUtil.getTeamIdx(chartEntity, seriesAttr.getFormId()) + ".userId.keyword";
                    TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms(ChartAggNameEnum.AGG_SECOND.getStr()).field(teamAttr);
                    termsAggregationBuilder.executionHint(ElasticConstant.EXECUTION_HINT);
                    sonAggregation = termsAggregationBuilder.size(ChartConstant.CHART_AGG_SIZE);
                } else {
                    // 特殊索引：这里只是拿了下index的type，所以无需更改
                    String teamType = IndexTypeEnum.getChildByParent(seriesAttr.getBusinessType()).getType();
                    ChildrenAggregationBuilder childrenAgg = JoinAggregationBuilders.children(ChartAggNameEnum.AGG_SECOND.getStr(), teamType);
                    TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms(ChartAggNameEnum.AGG_SECOND.getStr()).field("userId.keyword");
                    termsAggregationBuilder.executionHint(ElasticConstant.EXECUTION_HINT);
                    sonAggregation = childrenAgg.subAggregation(termsAggregationBuilder.size(ChartConstant.CHART_AGG_SIZE));
                }
            } else {
                TermsAggregationBuilder builder = AggregationBuilders.terms(ChartAggNameEnum.AGG_SECOND.getStr()).field(chartAttrAssemble(seriesAttr, isSingle)).size(ChartConstant.CHART_AGG_SIZE);
                builder.executionHint(ElasticConstant.EXECUTION_HINT);
                if (seriesAsc != null) {
                    builder.order(BucketOrder.key(seriesAsc));
                }
                sonAggregation = builder;
            }
            EsUtil.esSortChartStatisticsByFiled(sonAggregation, sortMap, valueAttr,null,null,null);
            //判断是否是计算字段作为值
            if (Objects.equals(FieldTypeEnum.COMPUTED_FIELD.getType(),valueAttr.getFieldType())) {
                List<String> fieldsList = new ArrayList<>();
                //判断单表还是多表，拼script
                JSONObject formulaInfo = valueAttr.getFormulaInfo();
                String formula = formulaInfo.getString("formula");
                try {
                    formula = EsUtil.getString(sourceBuilder, chartEntity.getFormIdAttr(), isSingle, fieldsList, formulaInfo, formula, Long.toString(seriesAttr.getFormId()));
                } catch (XbbException e) {
                    LOG.error("计算字段的公式格式有问题", e);
                    throw e;
                }
                switch (aggTypeEnum) {
                    case MAX:
                        sonAggregation.subAggregation(AggregationBuilders.max(ChartAggNameEnum.SUM_TOTAL.getStr()).script(new Script(formula)));
                        break;
                    case MIN:
                        sonAggregation.subAggregation(AggregationBuilders.min(ChartAggNameEnum.SUM_TOTAL.getStr()).script(new Script(formula)));
                        break;
                    case AVG:
                        sonAggregation.subAggregation(AggregationBuilders.avg(ChartAggNameEnum.SUM_TOTAL.getStr()).script(new Script(formula)));
                        break;
                    default:
                        sonAggregation.subAggregation(AggregationBuilders.sum(ChartAggNameEnum.SUM_TOTAL.getStr()).script(new Script(formula)));
                        break;
                    }
            }else{
                switch (aggTypeEnum) {
                    case MAX:
                        sonAggregation.subAggregation(AggregationBuilders.max(ChartAggNameEnum.SUM_TOTAL.getStr()).field(chartAttrAssemble(valueAttr, isSingle)));
                        break;
                    case MIN:
                        sonAggregation.subAggregation(AggregationBuilders.min(ChartAggNameEnum.SUM_TOTAL.getStr()).field(chartAttrAssemble(valueAttr, isSingle)));
                        break;
                    case AVG:
                        sonAggregation.subAggregation(AggregationBuilders.avg(ChartAggNameEnum.SUM_TOTAL.getStr()).field(chartAttrAssemble(valueAttr, isSingle)));
                        break;
                    default:
                        sonAggregation.subAggregation(AggregationBuilders.sum(ChartAggNameEnum.SUM_TOTAL.getStr()).field(chartAttrAssemble(valueAttr, isSingle)));
                        break;
                }
            }
            aggResult.subAggregation(sonAggregation);
        } else {
            // 排序
            FieldAttrPojo sortAttr = null;
            int sortIndex = 0;
            int resultSortIndex = 0;
            String side = PaasConstant.LEFT;
            String sortMapKey = null;
            // 左侧是0,右侧是1
            int sideFlag = PaasConstant.LEFT_SIDE_FLAG;
            if (CollectionUtils.isNotEmpty(valueAttrList) && Objects.nonNull(sortMap)){
                for (FieldAttrPojo item : valueAttrList) {
                    for (Map.Entry<String, String> entry : sortMap.entrySet()) {
                        String k = entry.getKey();
                        if (Objects.equals(chartEntity.getChartType(),ChartTypeEnum.BIAXIAL_CHART.getCode())){
                            if (Objects.equals(item.getAttr() + "&" + item.getFieldType() + "&" + sideFlag, k)) {
                                sortAttr = item;
                                sortMapKey = k;
                                resultSortIndex = sortIndex;
                                break;
                            }
                        }else if (Objects.equals(item.getAttr(),PaasConstant.COUNT) && Objects.equals(item.getAttr() + "&" + item.getFieldType() + "&" + item.getFormId(), k)) {
                            sortAttr = item;
                            sortMapKey = k;
                            resultSortIndex = sortIndex;
                            break;
                        }else if (Objects.equals(item.getAttr() + "&" + item.getFieldType(), k)) {
                            sortAttr = item;
                            sortMapKey = k;
                            resultSortIndex = sortIndex;
                            break;
                        }
                    }
                    if (Objects.nonNull(sortAttr)){
                        break;
                    }
                    sortIndex ++ ;
                }
            }
            if (CollectionUtils.isNotEmpty(valueAttrSecondList) && Objects.nonNull(sortMap) && Objects.isNull(sortAttr)){
                sideFlag = PaasConstant.RIGHT_SIDE_FLAG;
                for (FieldAttrPojo item : valueAttrSecondList) {
                    for (Map.Entry<String, String> entry : sortMap.entrySet()) {
                        String k = entry.getKey();
                        if (Objects.equals(chartEntity.getChartType(),ChartTypeEnum.BIAXIAL_CHART.getCode())){
                            if (Objects.equals(item.getAttr() + "&" + item.getFieldType() + "&" + sideFlag, k)) {
                                sortAttr = item;
                                sortMapKey = k;
                                side = PaasConstant.RIGHT;
                                resultSortIndex = sortIndex;
                                break;
                            }
                        }else if (Objects.equals(item.getAttr(),PaasConstant.COUNT) && Objects.equals(item.getAttr() + "&" + item.getFieldType() + "&" + item.getFormId(), k)) {
                            sortAttr = item;
                            sortMapKey = k;
                            side = PaasConstant.RIGHT;
                            resultSortIndex = sortIndex;
                            break;
                        }else if (Objects.equals(item.getAttr() + "&" + item.getFieldType() , k)) {
                            sortAttr = item;
                            sortMapKey = k;
                            side = PaasConstant.RIGHT;
                            resultSortIndex = sortIndex;
                            break;
                        }
                    }
                    if (Objects.nonNull(sortAttr)){
                        break;
                    }
                    sortIndex ++ ;
                }
            }
            sortAttr = ( null != sortAttr ) ? sortAttr : valueAttr;
            EsUtil.esSortChartStatisticsByFiled(aggResult, sortMap, sortAttr,side,resultSortIndex,sortMapKey);
            Integer sort = 0;
            sort = addAggregations(PaasConstant.LEFT,fieldAttrEntityAggTypeEnumMap,aggResult,sourceBuilder,chartEntity,isSingle,sort);
            addAggregations(PaasConstant.RIGHT,fieldAttrEntityAggTypeEnumSecondMap,aggResult,sourceBuilder,chartEntity,isSingle,sort);
        }
        sourceBuilder.aggregation(aggResult);
    }

    /**
     * 双轴图左侧右侧可能会添加相同的字段，要区分，添加aggregation
     * @param side
     * @param fieldAttrEntityAggTypeEnumMap
     * @param aggResult
     * @param sourceBuilder
     * @param chartEntity
     * @param isSingle
     */
    int addAggregations(String side, Map<FieldAttrPojo, AggTypeEnum> fieldAttrEntityAggTypeEnumMap, ValuesSourceAggregationBuilder aggResult, SearchSourceBuilder sourceBuilder, ChartEntity chartEntity, Boolean isSingle, int sort) throws XbbException {
        for (Map.Entry<FieldAttrPojo, AggTypeEnum> entry : fieldAttrEntityAggTypeEnumMap.entrySet()) {
            FieldAttrPojo fieldAttrPojo = entry.getKey();
            AggTypeEnum aggType = entry.getValue();
            if (Objects.equals(FieldTypeEnum.COMPUTED_FIELD.getType(), fieldAttrPojo.getFieldType())) {
                List<String> fieldsList = new ArrayList<>();
                //判断单表还是多表，拼script
                JSONObject formulaInfo = fieldAttrPojo.getFormulaInfo();
                String formula = formulaInfo.getString("formula");
                try {
                    formula = EsUtil.getString(sourceBuilder, chartEntity.getFormIdAttr(), isSingle, fieldsList, formulaInfo, formula, Long.toString(fieldAttrPojo.getFormId()));
                } catch (XbbException e) {
                    LOG.error("计算字段的公式格式有问题", e);
                    throw e;
                }
                switch (aggType) {
                    case MAX:
                        aggResult.subAggregation(AggregationBuilders.max(ChartAggNameEnum.SUM_TOTAL.getStr() + "&" + fieldAttrPojo.getFormId() + "&" + fieldAttrPojo.getAttr() +  "&" + side + "&" + (sort++)).script(new Script(formula)));
                        break;
                    case MIN:
                        aggResult.subAggregation(AggregationBuilders.min(ChartAggNameEnum.SUM_TOTAL.getStr() + "&" + fieldAttrPojo.getFormId() + "&" + fieldAttrPojo.getAttr() + "&" + side + "&"  + (sort++)).script(new Script(formula)));
                        break;
                    case AVG:
                        aggResult.subAggregation(AggregationBuilders.avg(ChartAggNameEnum.SUM_TOTAL.getStr() + "&" + fieldAttrPojo.getFormId() + "&" + fieldAttrPojo.getAttr() + "&" + side + "&"  + (sort++)).script(new Script(formula)));
                        break;
                    default:
                        aggResult.subAggregation(AggregationBuilders.sum(ChartAggNameEnum.SUM_TOTAL.getStr() + "&" + fieldAttrPojo.getFormId() + "&" + fieldAttrPojo.getAttr() + "&" + side + "&"  + (sort++)).script(new Script(formula)));
                        break;
                }
            } else {
                switch (aggType) {
                    case SUM:
                        aggResult.subAggregation(AggregationBuilders.sum(ChartAggNameEnum.SUM_TOTAL.getStr() + "&" + fieldAttrPojo.getFormId() + "&" + fieldAttrPojo.getAttr() + "&" + side + "&"  + (sort++)).field(chartAttrAssemble(fieldAttrPojo, isSingle)));
                        break;
                    case MAX:
                        aggResult.subAggregation(AggregationBuilders.max(ChartAggNameEnum.SUM_TOTAL.getStr() + "&" + fieldAttrPojo.getFormId() + "&" + fieldAttrPojo.getAttr() + "&" + side + "&"  + (sort++)).field(chartAttrAssemble(fieldAttrPojo, isSingle)));
                        break;
                    case MIN:
                        aggResult.subAggregation(AggregationBuilders.min(ChartAggNameEnum.SUM_TOTAL.getStr() + "&" + fieldAttrPojo.getFormId() + "&" + fieldAttrPojo.getAttr() + "&" + side + "&"  + (sort++)).field(chartAttrAssemble(fieldAttrPojo, isSingle)));
                        break;
                    case AVG:
                        aggResult.subAggregation(AggregationBuilders.avg(ChartAggNameEnum.SUM_TOTAL.getStr() + "&" + fieldAttrPojo.getFormId() + "&" + fieldAttrPojo.getAttr() + "&" + side + "&"  + (sort++)).field(chartAttrAssemble(fieldAttrPojo, isSingle)));
                        break;
                    case COUNT:
                        aggResult.subAggregation(AggregationBuilders.count(ChartAggNameEnum.SUM_TOTAL.getStr() + "&" + fieldAttrPojo.getFormId() + "&" + fieldAttrPojo.getAttr() + "&" + side + "&"  + (sort++)).field(chartAttrAssemble(fieldAttrPojo, isSingle)));
                        break;
                    default:
                        break;
                }
            }
        }
        return sort;
    }

    private Map<String, String> valueListAnalysis(FieldAttrPojo field, String corpId, List<String> values, ChartEntity chartEntity, BaseDTO baseDTO) throws XbbException{
        return chartResultHelp.valueListAnalysis(field, corpId, values, chartEntity, true, null, true, baseDTO,null);
    }

    private Map<String, String> valueListAnalysis(FieldAttrPojo field, String corpId, List<String> values, ChartEntity chartEntity, Map<String, String> dataIdToEsId, BaseDTO baseDTO) throws XbbException{
        return chartResultHelp.valueListAnalysis(field, corpId, values, chartEntity, false, dataIdToEsId, false, baseDTO,null);
    }

    /**
     * 递归解析桶装载统计数据
     *
     * @param aggregations            es查询结果
     * @param chartStatisticsPojoList 递归组装的结果
     * @param statisticsPojoMap       上一层的数据 Map
     * @author yuqian
     * @date 2019/4/11 10:58
     * @since v1.0
     */
    private void recurrenceParseBucket(Aggregations aggregations, List<LinkedHashMap<String, ChartStatisticsPojo>> chartStatisticsPojoList,
                                       Map<String, ChartStatisticsPojo> statisticsPojoMap) {
        List<Aggregation> aggregationList = aggregations.asList();
        for (Aggregation aggregation : aggregationList) {
            String aggKey = aggregation.getName();
            MultiBucketsAggregation terms = null;
            if (aggregation instanceof ParsedChildren) {
                ParsedChildren childrenAgg = (ParsedChildren) aggregation;
                Aggregations childrenAggregations = childrenAgg.getAggregations();
                List<Aggregation> childList = childrenAggregations.asList();
                for (Aggregation e : childList) {
                    terms = e instanceof ParsedTerms ? (ParsedTerms) e : null;
                }
            } else if (aggregation instanceof ParsedValueCount) {
                ParsedValueCount parsedValueCount = (ParsedValueCount) aggregation;
                ChartStatisticsPojo chartStatisticsPojo = new ChartStatisticsPojo();
                chartStatisticsPojo.setKey(parsedValueCount.getName());
                chartStatisticsPojo.setValue(String.valueOf((int) parsedValueCount.getValue()));
                chartStatisticsPojo.setOriginValue(String.valueOf((int) parsedValueCount.getValue()));
                statisticsPojoMap.put(parsedValueCount.getName(), chartStatisticsPojo);
                continue;
            } else if (aggregation instanceof ParsedSum) {
                Sum sum = (Sum) aggregation;
                ChartStatisticsPojo chartStatisticsPojo = new ChartStatisticsPojo();
                chartStatisticsPojo.setKey(sum.getName());
                // TODO 汇总的字段的小数设置
                String valueAsString = sum.getValueAsString();
                if (valueAsString.contains(PaasConstant.ES_INFINITY)){
                    valueAsString = "0.0";
                }
                chartStatisticsPojo.setValue(StringUtil.formatDouble(Double.valueOf(valueAsString), 6, 1));
                chartStatisticsPojo.setOriginValue(StringUtil.formatDouble(Double.valueOf(valueAsString), 6, 1));
                statisticsPojoMap.put(sum.getName(), chartStatisticsPojo);
                continue;
            }  else if (aggregation instanceof ParsedAvg) {
                ParsedAvg avg = (ParsedAvg) aggregation;
                ChartStatisticsPojo chartStatisticsPojo = new ChartStatisticsPojo();
                chartStatisticsPojo.setKey(avg.getName());
                // TODO 汇总的字段的小数设置
                String valueAsString = avg.getValueAsString();
                if (valueAsString.contains(PaasConstant.ES_INFINITY)){
                    valueAsString = "0.0";
                }
                chartStatisticsPojo.setValue(StringUtil.formatDouble(Double.valueOf(valueAsString), 6, 1));
                chartStatisticsPojo.setOriginValue(StringUtil.formatDouble(Double.valueOf(valueAsString), 6, 1));
                statisticsPojoMap.put(avg.getName(), chartStatisticsPojo);
                continue;
            }  else if (aggregation instanceof ParsedMax) {
                ParsedMax max = (ParsedMax) aggregation;
                ChartStatisticsPojo chartStatisticsPojo = new ChartStatisticsPojo();
                chartStatisticsPojo.setKey(max.getName());
                // TODO 汇总的字段的小数设置
                String valueAsString = max.getValueAsString();
                if (valueAsString.contains(PaasConstant.ES_INFINITY)){
                    valueAsString = "0.0";
                }
                chartStatisticsPojo.setValue(StringUtil.formatDouble(Double.valueOf(valueAsString), 6, 1));
                chartStatisticsPojo.setOriginValue(StringUtil.formatDouble(Double.valueOf(valueAsString), 6, 1));
                statisticsPojoMap.put(max.getName(), chartStatisticsPojo);
                continue;
            }  else if (aggregation instanceof ParsedMin) {
                ParsedMin min = (ParsedMin) aggregation;
                ChartStatisticsPojo chartStatisticsPojo = new ChartStatisticsPojo();
                chartStatisticsPojo.setKey(min.getName());
                // TODO 汇总的字段的小数设置
                String valueAsString = min.getValueAsString();
                if (valueAsString.contains(PaasConstant.ES_INFINITY)){
                    valueAsString = "0.0";
                }
                chartStatisticsPojo.setValue(StringUtil.formatDouble(Double.valueOf(valueAsString), 6, 1));
                chartStatisticsPojo.setOriginValue(StringUtil.formatDouble(Double.valueOf(valueAsString), 6, 1));
                statisticsPojoMap.put(min.getName(), chartStatisticsPojo);
                continue;
            }  else if (aggregation instanceof ParsedSimpleValue) {
                ParsedSimpleValue sv = (ParsedSimpleValue) aggregation;
                ChartStatisticsPojo chartStatisticsPojo = new ChartStatisticsPojo();
                chartStatisticsPojo.setKey(sv.getName());
                chartStatisticsPojo.setValue(sv.getValueAsString());
                chartStatisticsPojo.setOriginValue(sv.getValueAsString());
                statisticsPojoMap.put(sv.getName(), chartStatisticsPojo);
                continue;
            } else {
                terms = (MultiBucketsAggregation) aggregation;
            }
            if (terms != null) {
                for (MultiBucketsAggregation.Bucket bk : terms.getBuckets()) {
                    ChartStatisticsPojo chartStatisticsPojo = new ChartStatisticsPojo();
                    chartStatisticsPojo.setKey(aggKey);
                    Object obj = bk.getKey();
                    if (obj instanceof ZonedDateTime) {
                        obj = ((ZonedDateTime) obj).toLocalDateTime().toInstant(ZoneOffset.ofHours(0)).toEpochMilli();
                    }
                    String key = String.valueOf(obj);
                    chartStatisticsPojo.setValue(key);
                    chartStatisticsPojo.setOriginValue(key);
                    LinkedHashMap<String, ChartStatisticsPojo> chartStatisticsPojoMap = new LinkedHashMap<>();
                    chartStatisticsPojo.setSub(new ArrayList<>());
                    chartStatisticsPojoMap.put(terms.getName(), chartStatisticsPojo);
                    chartStatisticsPojoList.add(chartStatisticsPojoMap);
                    recurrenceParseBucket(bk.getAggregations(), chartStatisticsPojo.getSub(), chartStatisticsPojoMap);
                }
            }
        }
    }
    /*
     * 指标图聚合解析
     **/
    private String parseTargetBucket(Aggregations aggregations, FieldAttrPojo summaryAttrPojo, List<LinkedHashMap<String, ChartStatisticsPojo>> chartStatisticsPojoList, int hasGroupField) {
        List<Aggregation> aggregationList = aggregations.asList();
        String totalSum ="";
        for (Aggregation aggregation : aggregationList) {
            if (hasGroupField == 1) {
                //无分组字段
                if (aggregation instanceof ParsedValueCount) {
                    totalSum = ((ParsedValueCount) aggregation).getValueAsString();
                } else if (aggregation instanceof ParsedSum) {
                    totalSum = ((Sum) aggregation).getValueAsString();
                } else if (aggregation instanceof ParsedAvg) {
                    totalSum = ((Avg) aggregation).getValueAsString();
                } else if (aggregation instanceof ParsedMax) {
                    totalSum = ((ParsedMax) aggregation).getValueAsString();
                } else if (aggregation instanceof ParsedMin) {
                    totalSum = ((ParsedMin) aggregation).getValueAsString();
                }
                break;
            }
            String aggKey = aggregation.getName();
            MultiBucketsAggregation terms = null;
            if (aggregation instanceof ParsedSimpleValue){
                 totalSum = ((ParsedSimpleValue) aggregation).getValueAsString();
            } else {
                terms = (MultiBucketsAggregation) aggregation;
            }
            if (terms != null) {
                for (MultiBucketsAggregation.Bucket bk : terms.getBuckets()) {
                    ChartStatisticsPojo chartStatisticsPojo = new ChartStatisticsPojo();
                    chartStatisticsPojo.setKey(aggKey);
                    String key;
                    if (bk instanceof ParsedDateHistogram.ParsedBucket) {
                        // 直接拿key在时间相关类型时会被转为UTC，所以选择用反射拿
                        key = String.valueOf(ReflectHelper.valueGet(bk, "key", false));
                    } else {
                        key = String.valueOf(bk.getKey());
                    }
                    chartStatisticsPojo.setValue(key);
                    chartStatisticsPojo.setOriginValue(key);
                    LinkedHashMap<String, ChartStatisticsPojo> chartStatisticsPojoMap = new LinkedHashMap<>();
                    chartStatisticsPojo.setSub(new ArrayList<>());
                    chartStatisticsPojoMap.put(terms.getName(), chartStatisticsPojo);
                    chartStatisticsPojoList.add(chartStatisticsPojoMap);
                    recurrenceParseBucket(bk.getAggregations(), chartStatisticsPojo.getSub(), chartStatisticsPojoMap);
                }
            }
        }
        // 小数精度
        Integer accuracy = 2;
        // 是否使用百分比
        Integer percentUsed = 0;
        // 是否使用千分符
        Integer groupingUsed = 0;
        if (summaryAttrPojo != null) {
            accuracy = summaryAttrPojo.getAccuracy();
            accuracy = accuracy == null ? 0 : accuracy;
            if (Objects.nonNull(summaryAttrPojo.getPercentUsed())) {
                percentUsed = summaryAttrPojo.getPercentUsed();
            }
            groupingUsed = summaryAttrPojo.getGroupingUsed() == null ? summaryAttrPojo.getAmountFlag() : summaryAttrPojo.getGroupingUsed();
        }
        String finalSum = attrDecimalPrecisionHelper.getNumberFormat(totalSum, accuracy, groupingUsed, percentUsed);
        return finalSum;
    }
    /**
     * 递归解析桶装载统计数据（图表）
     *
     * @param aggregations            es查询结果
     * @param chartStatisticsPojoList 解析结果储存对象
     * @author zhouwq
     * @date 2019/4/15 18:38
     */
    private static void recurrenceParseBucket(Aggregations aggregations, List<LinkedHashMap<String, ChartStatisticsPojo>> chartStatisticsPojoList) {
        List<Aggregation> aggregationList = aggregations.asList();
        for (Aggregation aggregation : aggregationList) {
            if (CustomChartConstant.SUM_TYPE.equals(aggregation.getType())) {
                Sum sum = (Sum) aggregation;
                LinkedHashMap<String, ChartStatisticsPojo> chartStatisticsPojoMap = new LinkedHashMap<>();
                ChartStatisticsPojo chartStatisticsPojo = new ChartStatisticsPojo();
                chartStatisticsPojo.setKey(sum.getName());
                chartStatisticsPojo.setValue(PaasConstant.ES_INFINITY.equals(sum.getValueAsString()) ? "0" : sum.getValueAsString());
                chartStatisticsPojoMap.put(sum.getName(), chartStatisticsPojo);
                chartStatisticsPojoList.add(chartStatisticsPojoMap);
            } else if (CustomChartConstant.MIN_TYPE.equals(aggregation.getType())) {
                Min min = (Min) aggregation;
                LinkedHashMap<String, ChartStatisticsPojo> chartStatisticsPojoMap = new LinkedHashMap<>();
                ChartStatisticsPojo chartStatisticsPojo = new ChartStatisticsPojo();
                chartStatisticsPojo.setKey(min.getName());
                chartStatisticsPojo.setValue(PaasConstant.ES_INFINITY.equals(min.getValueAsString()) ? "0" : min.getValueAsString());
                chartStatisticsPojoMap.put(min.getName(), chartStatisticsPojo);
                chartStatisticsPojoList.add(chartStatisticsPojoMap);
            } else if (CustomChartConstant.MAX_TYPE.equals(aggregation.getType())) {
                Max max = (Max) aggregation;
                LinkedHashMap<String, ChartStatisticsPojo> chartStatisticsPojoMap = new LinkedHashMap<>();
                ChartStatisticsPojo chartStatisticsPojo = new ChartStatisticsPojo();
                chartStatisticsPojo.setKey(max.getName());
                chartStatisticsPojo.setValue(PaasConstant.ES_INFINITY.equals(max.getValueAsString()) ? "0" : max.getValueAsString());
                chartStatisticsPojoMap.put(max.getName(), chartStatisticsPojo);
                chartStatisticsPojoList.add(chartStatisticsPojoMap);
            } else if (CustomChartConstant.AVG_TYPE.equals(aggregation.getType())) {
                Avg avg = (Avg) aggregation;
                LinkedHashMap<String, ChartStatisticsPojo> chartStatisticsPojoMap = new LinkedHashMap<>();
                ChartStatisticsPojo chartStatisticsPojo = new ChartStatisticsPojo();
                chartStatisticsPojo.setKey(avg.getName());
                chartStatisticsPojo.setValue(PaasConstant.ES_INFINITY.equals(avg.getValueAsString()) ? "0" : avg.getValueAsString());
                chartStatisticsPojoMap.put(avg.getName(), chartStatisticsPojo);
                chartStatisticsPojoList.add(chartStatisticsPojoMap);
            } else if (CustomChartConstant.COUNT_TYPE.equals(aggregation.getType())) {
                ValueCount vc = (ValueCount) aggregation;
                LinkedHashMap<String, ChartStatisticsPojo> chartStatisticsPojoMap = new LinkedHashMap<>();
                ChartStatisticsPojo chartStatisticsPojo = new ChartStatisticsPojo();
                chartStatisticsPojo.setKey(vc.getName());
                chartStatisticsPojo.setValue(PaasConstant.ES_INFINITY.equals(vc.getValueAsString()) ? "0" : vc.getValueAsString());
                chartStatisticsPojoMap.put(vc.getName(), chartStatisticsPojo);
                chartStatisticsPojoList.add(chartStatisticsPojoMap);
            } else if (CustomChartConstant.SIMPLE_VALUE.equals(aggregation.getType())) {
                SimpleValue sv = (SimpleValue) aggregation;
                LinkedHashMap<String, ChartStatisticsPojo> chartStatisticsPojoMap = new LinkedHashMap<>();
                ChartStatisticsPojo chartStatisticsPojo = new ChartStatisticsPojo();
                chartStatisticsPojo.setKey(sv.getName());
                chartStatisticsPojo.setValue(PaasConstant.ES_INFINITY.equals(sv.getValueAsString()) ? "0" : sv.getValueAsString());
                chartStatisticsPojoMap.put(sv.getName(), chartStatisticsPojo);
                chartStatisticsPojoList.add(chartStatisticsPojoMap);
            }else{
                MultiBucketsAggregation terms = null;
                if(Objects.equals(CustomChartConstant.DATE_HISTOGRAM,aggregation.getType())){
                    terms = (Histogram)aggregation;
                } else if (Objects.equals(aggregation.getType(), CustomChartConstant.CHILDREN)) {
                    ParsedChildren childrenAgg = (ParsedChildren) aggregation;
                    Aggregations childrenAggregations = childrenAgg.getAggregations();
                    List<Aggregation> childList = childrenAggregations.asList();
                    for (Aggregation e : childList) {
                        terms = e instanceof ParsedTerms ? (ParsedTerms) e : null;
                    }
                } else {
                    terms = (Terms) aggregation;
                }
                if (terms != null) {
                    for (MultiBucketsAggregation.Bucket bk : terms.getBuckets()) {
                        LinkedHashMap<String, ChartStatisticsPojo> chartStatisticsPojoMap = new LinkedHashMap<>();
                        Object obj = bk.getKey();
                        if (obj instanceof ZonedDateTime) {
                            obj = ((ZonedDateTime) obj).toLocalDateTime().toInstant(ZoneOffset.ofHours(0)).toEpochMilli();
                        }
                        ChartStatisticsPojo chartStatisticsPojo = new ChartStatisticsPojo(terms.getName(), String.valueOf(obj), bk.getDocCount());
                        if (bk.getAggregations().asList().size() > 0) {
                            chartStatisticsPojo.setSub(new ArrayList<>());
                            chartStatisticsPojoMap.put(terms.getName(), chartStatisticsPojo);
                            chartStatisticsPojoList.add(chartStatisticsPojoMap);
                            recurrenceParseBucket(bk.getAggregations(), chartStatisticsPojo.getSub());
                        } else {
                            chartStatisticsPojoMap.put(terms.getName(), chartStatisticsPojo);
                            ChartStatisticsPojo statisticsPojo = new ChartStatisticsPojo();
                            statisticsPojo.setValue(String.valueOf(bk.getDocCount()));
                            chartStatisticsPojoMap.put("count", statisticsPojo);
                            chartStatisticsPojoList.add(chartStatisticsPojoMap);
                        }
                    }
                }
            }
        }
    }

    /**
     * 查询表展示
     *
     * @param chartEntity      图表实体类
     * @param boolQueryBuilder 搜索条件
     * @param pageHelper       分页
     * @return JSONObject 结果集
     * @throws XbbException error
     */
    private JSONObject chartsAnalysisByQueryTable(ChartEntity chartEntity, SearchSourceBuilder sourceBuilder,
                                                  BoolQueryBuilder boolQueryBuilder, PageHelper pageHelper, ChartResultPojo chartResultPojo, SearchRequest searchRequest) throws XbbException {
        Boolean exportFlag = chartResultPojo.getExportFlag();
        JSONObject result = new JSONObject();
        JSONArray tableHead = new JSONArray();
        Map<JSONObject, FieldAttrPojo> parseAttrMap = new HashMap<>(16);
        boolean hasIntersection;
        List<FieldAttrPojo> fieldAttrPojoList = JSONArray.parseArray(chartEntity.getDisplayAttr().toJSONString(), FieldAttrPojo.class);
        //数据查询表先拼装展示数据
        displayAttrAssemble(fieldAttrPojoList, null, sourceBuilder, tableHead, parseAttrMap, null, chartEntity);
        Map<String, String> sortMap = getSortMap(chartEntity, chartResultPojo.getSortMap());
        EsUtil.esSortByFiled(sourceBuilder, sortMap, parseAttrMap, null, chartEntity);
        //拼装筛选条件
        hasIntersection = EsUtil.parseConditionIntersection(boolQueryBuilder, chartEntity, false);
        customHelp.customIndexQueryDefaultFilter(chartEntity, boolQueryBuilder);
        //固定最大分页
        if (pageHelper.getCurrentPageNum() * pageHelper.getPageSize() > ChartConstant.MAX_SIZE) {
            pageHelper.setCurrentPageNum(ChartConstant.MAX_SIZE / pageHelper.getPageSize());
        }
        //设置分页
        PageRequest pageRequest = EsUtil.setPage(sourceBuilder, pageHelper.getCurrentPageNum(), pageHelper.getPageSize());
        searchRequest.source(sourceBuilder);
        long rowCount = 0;
        //是否展示关联经销商的标识
        boolean linkDistributor = false;
        Map<Long, String> nameMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (int i = 0; i < tableHead.size(); i++) {
            JSONObject jsonObject = tableHead.getJSONObject(i);
            if (Objects.equals(jsonObject.getInteger("fieldType"), FieldTypeEnum.LINK_BUSINESS_SINGLE.getType())) {
                linkDistributor = true;
            }
        }
        //ES查询表的数据
        try {
            if (hasIntersection) {
                //TODO
                if (EsUtil.getSingle(chartEntity)) {
                    List<ChartFieldsAnalysisEntityExt> esList = new ArrayList<>();
                    //判断是否为导出情况，导出情况下查询方法使用scroll查出超过1W条的数据
                    if (exportFlag != null && exportFlag) {
                        esList = xbbElasticsearchRestTemplate.getScrollListForExport(ChartFieldsAnalysisEntityExt.class, searchRequest);
                        biSubFormDataSingleHandle.handleSubFormData(esList, chartEntity, pageHelper, tableHead, boolQueryBuilder, searchRequest);
                    } else {
                        XbbAggregatedPage<ChartFieldsAnalysisEntityExt> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest, ChartFieldsAnalysisEntityExt.class);
                        esList = esEntities.getContent();
                        if (searchRequest.indices()[0].contains(IndexTypeEnum.IDX_SAAS_DISTRIBUTOR_ACCOUNT.getIndex()) && linkDistributor){
                            List<Long> idList = new ArrayList<>();
                            esList.forEach(item -> idList.add(item.getData().getLong(DistributorAccountEnum.DISTRIBUTOR_NAME.getAttr())));
                            List<CustomerEntityExt> customerEntityExts = customerModel.getByKeys(idList, chartEntity.getCorpid());
                            customerEntityExts.forEach(item -> nameMap.put(item.getId(), item.getData().getString(DistributorEnum.NAME.getAttr())));
                            esList.forEach(item -> item.getData().put(DistributorAccountEnum.DISTRIBUTOR_NAME_LINK_TEXT.getAttr(), nameMap.get(item.getData().getLong(DistributorAccountEnum.DISTRIBUTOR_NAME.getAttr()))));
                        }
                        rowCount = esEntities.getTotalElements();
                    }
                    result = encapsulateTableData(tableHead, esList, null, chartEntity, parseAttrMap, chartResultPojo);
                } else {
                    List<StatisticBiFormDataEntity> esList = new ArrayList<>();
                    //判断是否为导出情况，导出情况下查询方法使用scroll查出超过1W条的数据
                    if (exportFlag != null && exportFlag) {
                        esList = xbbElasticsearchRestTemplate.getScrollListForExport(StatisticBiFormDataEntity.class, searchRequest);
                        biSubFormDataMultiHandle.handleSubFormData(esList, chartEntity, pageHelper, tableHead, boolQueryBuilder, searchRequest);
                    } else {
                        XbbAggregatedPage<StatisticBiFormDataEntity> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest, StatisticBiFormDataEntity.class);
                        //TODO
                        esList = esEntities.getContent();
                        rowCount = esEntities.getTotalElements();
                    }
                    result = encapsulateTableData(tableHead, null, esList, chartEntity, parseAttrMap, chartResultPojo);
                }
            } else {
                result = encapsulateTableData(tableHead, null, null, chartEntity, parseAttrMap, chartResultPojo);
            }
        } catch (XbbException | IllegalAccessException e) {
            LOG.error("解析查询表出错", e);
        }
        pageHelper.setRowsCount((int) (rowCount));
        result.put("realRowsCount", rowCount);
        if (rowCount > ChartConstant.MAX_SIZE) {
            pageHelper.setRowsCount(ChartConstant.MAX_SIZE);
        }
        return result;
    }

    /**
     * 统计表展示
     *
     * @param chartEntity      图表实体类
     * @param boolQueryBuilder 搜索条件
     * @param pageHelper       分页
     * @return JSONObject 结果集
     * @throws XbbException error
     */
    private JSONObject chartsAnalysisByStatisticsTable(ChartEntity chartEntity, SearchSourceBuilder sourceBuilder,
                                                       BoolQueryBuilder boolQueryBuilder, PageHelper pageHelper, ChartResultPojo chartResultPojo, SearchRequest searchRequest) throws XbbException {
        Boolean exportFlag = chartResultPojo.getExportFlag();
        Integer pageTurn = chartResultPojo.getPageTurn();
        Aggregations aggregations = null;
        JSONObject result;
        JSONArray tableHead = new JSONArray();
        // 表头分组字段实体映射(现在加上汇总字段)
        Map<JSONObject, FieldAttrPojo> parseAttrMap = new HashMap<>(16);
        // 是否有交集
        boolean hasIntersection;
        List<FieldAttrPojo> groupAttrList = JSONArray.parseArray(chartEntity.getRowGroupAttr().toJSONString(), FieldAttrPojo.class);
        List<FieldAttrPojo> summaryAttrList = JSONArray.parseArray(chartEntity.getSummaryAttr().toJSONString(), FieldAttrPojo.class);
        // 汇总字段属性映射
        Map<String, FieldAttrPojo> summaryAttrMap = new HashMap<>(16);
        //展现数据拼接,返回的是自行拼接的表头key 和 es 字段对应
        displayAttrAssemble(groupAttrList, summaryAttrList, null, tableHead,parseAttrMap, summaryAttrMap, chartEntity);
        if (BasicConstant.ONE.equals(pageTurn)) {
            result = encapsulateStatisticsTable(tableHead, null, pageHelper, chartEntity, parseAttrMap, summaryAttrMap, BasicConstant.ONE, exportFlag, chartResultPojo);
            return result;
        }
        hasIntersection = EsUtil.parseConditionIntersection(boolQueryBuilder, chartEntity, false);
        customHelp.customIndexQueryDefaultFilter(chartEntity, boolQueryBuilder);
        //统计汇总条件拼接
        EsUtil.statisticTableAggregation(sourceBuilder, groupAttrList, summaryAttrList, chartResultPojo.getSortStatisticsMap(), chartEntity);
        searchRequest.source(sourceBuilder);
        //ES查询表的数据
        if (hasIntersection) {
            // 执行语句获取聚合结果
            aggregations = xbbElasticsearchRestTemplate.query(searchRequest);
        }
        //都已经到这里了不妨全走一遍pageTurn 直接 为 0
        result = encapsulateStatisticsTable(tableHead, aggregations, pageHelper, chartEntity, parseAttrMap, summaryAttrMap, BasicConstant.ZERO, exportFlag, chartResultPojo);
        return result;
    }

    /**
     * 指标图展示
     *
     * @param chartEntity      图表实体类
     * @param boolQueryBuilder 搜索条件
     * @param pageHelper       分页
     * @return JSONObject 结果集
     * @throws XbbException error
     */
    private JSONObject chartsAnalysisByTarget(ChartEntity chartEntity, SearchSourceBuilder sourceBuilder,
                                                       BoolQueryBuilder boolQueryBuilder, PageHelper pageHelper, ChartResultPojo chartResultPojo, SearchRequest searchRequest) throws XbbException {
        Boolean exportFlag = chartResultPojo.getExportFlag();
        Integer pageTurn = chartResultPojo.getPageTurn();
        Aggregations aggregations = null;
        JSONObject result;
        JSONArray tableHead = new JSONArray();
        // 表头分组字段实体映射(现在加上汇总字段)
        Map<JSONObject, FieldAttrPojo> parseAttrMap = new HashMap<>(16);
        // 是否有交集
        boolean hasIntersection;
        List<FieldAttrPojo> groupAttrList = JSONArray.parseArray(chartEntity.getRowGroupAttr().toJSONString(), FieldAttrPojo.class);
        List<FieldAttrPojo> summaryAttrList = JSONArray.parseArray(chartEntity.getSummaryAttr().toJSONString(), FieldAttrPojo.class);
        List<FieldAttrPojo> secondTargetList = null;
        if(Objects.nonNull(chartEntity.getSecondTargetAttr())){
            secondTargetList = JSONArray.parseArray(chartEntity.getSecondTargetAttr().toJSONString(), FieldAttrPojo.class);
        }
        // 汇总字段属性映射
        Map<String, FieldAttrPojo> summaryAttrMap = new HashMap<>(16);
        // 如果是副指标指标图
        List<String> secondTargetKey = new ArrayList<>();
        if (Objects.equals(chartEntity.getChartType(),ChartTypeEnum.SECOND_TARGET_CHART.getCode())){
            if (CollectionUtils.isEmpty(secondTargetList)){
                throw new XbbException(ChartErrorCodeEnum.API_ERROR_310001, ChartErrorCodeEnum.API_ERROR_310001.getMsg());
            }
            FieldAttrPojo fieldAttrPojo = secondTargetList.get(0);
            JSONArray advancedComputing = fieldAttrPojo.getAdvancedComputing();
            if (CollectionsUtil.isNotEmpty(advancedComputing) && !Objects.equals(advancedComputing.getString(0), AdvancedComputingFirstEnum.NONE.getAlias())) {
                // 将副指标里面的统计时间封装成分组字段
                FieldAttrPojo timeAttr = JSONObject.parseObject(chartEntity.getTimeAttr().toJSONString(),FieldAttrPojo.class);
                timeAttr.setLabel(timeAttr.getAttrName());
                timeAttr.setLabelName(timeAttr.getAttrName());
                String timeDimension = fieldAttrPojo.getTimeDimension();
                timeAttr.setDateGroupType(timeDimension);
                groupAttrList.add(timeAttr);
                chartEntity.setRowGroupAttr(JSONArray.parseArray(JSON.toJSONString(groupAttrList)));
                //将时间维度封装成筛选条件
                JSONArray filter = chartEntity.getFilter();
                if (Objects.isNull(filter)){
                    filter = new JSONArray();
                }
                List<Long> valueList = chartResultHelp.getSecondTargetFilter(timeDimension,advancedComputing,secondTargetKey, null);
                if (CollectionUtils.isNotEmpty(valueList)){
                    JSONObject conditionJson = (JSONObject) JSONObject.toJSON(timeAttr);
                    conditionJson.put("symbol", "range");
                    conditionJson.put("value", valueList);
                    filter.add(conditionJson);
                }
                chartEntity.setFilter(filter);
            }
        }

        //展现数据拼接,返回的是自行拼接的表头key 和 es 字段对应
        displayAttrAssemble(groupAttrList, summaryAttrList, null, tableHead, parseAttrMap, summaryAttrMap, chartEntity);
        if (BasicConstant.ONE.equals(pageTurn)) {
            result = encapsulateTargetChart(tableHead,null, pageHelper, chartEntity, parseAttrMap, summaryAttrMap, BasicConstant.ONE, exportFlag, chartResultPojo,secondTargetKey);
            return result;
        }
        Map<String, String> sortMap = getSortMap(chartEntity, chartResultPojo.getSortStatisticsMap());
        //拼装指标图的归属人条件
        //assembleBelongerCondition(chartEntity, chartResultPojo);
        //拼装筛选条件
        hasIntersection = EsUtil.parseConditionIntersection(boolQueryBuilder, chartEntity, false);
        customHelp.customIndexQueryDefaultFilter(chartEntity, boolQueryBuilder);
        //统计汇总条件拼接
        EsUtil.targetChartAggregation(sourceBuilder, groupAttrList, summaryAttrList, sortMap, chartEntity);
        searchRequest.source(sourceBuilder);
        //ES查询表的数据
        if (hasIntersection) {
            // 执行语句获取聚合结果
            aggregations = xbbElasticsearchRestTemplate.query(searchRequest);
        }
        //都已经到这里了不妨全走一遍pageTurn 直接 为 0
        result = encapsulateTargetChart(tableHead, aggregations, pageHelper, chartEntity, parseAttrMap, summaryAttrMap, BasicConstant.ZERO, exportFlag, chartResultPojo,secondTargetKey);
        return result;
    }

    /**
     *  统计表展示，包含行列分组逻辑
     *
     *  先查询es,将结果集存入redis中,在五分钟内从redis中取值
     *          方案1：查三次es,行分组聚合es,列分组聚合es,将行列分组字段合并聚合es
     *          方案2（弃用）：查三次es,行分组聚合es,列分组聚合es,汇总script脚本es,为解决一次性查询行列分组聚合造成数据结构混乱,避免行分组中间字段为空造成列分组字段下都为空
     *
     * @param chartEntity      图表实体类
     * @param sourceBuilder
     * @param boolQueryBuilder   搜索条件
     * @param pageHelper    分页条件
     * @param chartResultPojo
     * @param searchRequest
     * @return JSONObject
     */
    private JSONObject chartDataByStatisticsTable(ChartEntity chartEntity, SearchSourceBuilder sourceBuilder, BoolQueryBuilder boolQueryBuilder,
                                                  PageHelper pageHelper, ChartResultPojo chartResultPojo, SearchRequest searchRequest) throws XbbException {
        JSONObject table = new JSONObject();
        JSONObject head = new JSONObject();
        JSONArray summary;
        JSONObject redisMap;
        Map<Integer, List<ChartStatisticsPojo>> rowIndexResultMap;
        List<ChartStatisticsPojo> rowDataList = null;
        Map<String, Map<String, Object>> aggsBucketsMap;
        List<ChartStatisticsPojo> body;
        int rowsCount;
        int pageTotal;
        int colTotal;
        JSONObject formIdAttr = chartEntity.getFormIdAttr();
        // 行列分组和总分组
        JSONArray rowGroupAttr = chartEntity.getRowGroupAttr();
        JSONArray colGroupAttr = chartEntity.getColGroupAttr();
        JSONArray summaryAttr = chartEntity.getSummaryAttr();
        List<FieldAttrPojo> rowGroupAttrList = new ArrayList<>();
        List<FieldAttrPojo> colGroupAttrList = new ArrayList<>();
        List<FieldAttrPojo> summaryAttrList = new ArrayList<>();
        List<FieldAttrPojo> groupAttrList = new ArrayList<>();
        if (rowGroupAttr != null) {
            rowGroupAttrList = JSONArray.parseArray(rowGroupAttr.toJSONString(), FieldAttrPojo.class);
            groupAttrList.addAll(rowGroupAttrList);
        }
        if (colGroupAttr != null) {
            colGroupAttrList = JSONArray.parseArray(colGroupAttr.toJSONString(), FieldAttrPojo.class);
            groupAttrList.addAll(colGroupAttrList);
        }
        if (summaryAttr != null) {
            summaryAttrList = JSONArray.parseArray(summaryAttr.toJSONString(), FieldAttrPojo.class);
            for (int i = 0; i < summaryAttrList.size(); i++) {
                summaryAttrList.get(i).setGroupIndex(i);
            }
        }
        // 是否同环比
        boolean isYearChain = EsUtil.isYearChain(chartEntity);
        // 同环比不汇总
        if (isYearChain) {
            chartEntity.setSum(-1);
        }
        // 汇总字段属性映射
        Map<String, FieldAttrPojo> summaryAttrMap = summaryAttrList.stream().collect(Collectors.toMap(item ->{
            String formId = item.getFormId().toString();
            String attr = item.getAttr();
            String aggName = attr + "&" + item.getFieldType() + "&" + item.getGroupIndex();
            if (attr.contains("count") && formIdAttr != null && formIdAttr.size() > 0) {
                aggName = formId + aggName;
            }
            return aggName;
        }, fieldAttrPojo -> fieldAttrPojo,(u,v) -> u, LinkedHashMap::new));

        List<ChartStatisticsPojo> headChild = new ArrayList<>();
        if (colGroupAttr != null) {
            colGroupAttr.forEach(item -> {
                FieldAttrPojo fieldAttrPojo = JSONObject.parseObject(item.toString(), FieldAttrPojo.class);
                String labelName = fieldAttrPojo.getLabelName();
                String label = fieldAttrPojo.getLabel();
                String attrName = fieldAttrPojo.getAttrName();
                ChartStatisticsPojo pojo = new ChartStatisticsPojo();
                pojo.setKey(fieldAttrPojo.getAttr() + "&" + fieldAttrPojo.getFieldType());
                pojo.setValue(labelName);
                if (Objects.equals(labelName,label)) {
                    if (FieldTypeEnum.SUB_FORM.getType().intValue() == fieldAttrPojo.getFieldType()) {
                        pojo.setValue(attrName);
                    } else {
                        pojo.setValue(Arrays.asList(label.split("--")).get(0) + "--" + attrName);
                    }
                }
                pojo.setHead(true);
                pojo.setFormId(fieldAttrPojo.getFormId());
                if (fieldAttrPojo.getDateGroupType() != null) {
                    pojo.setDateGroupType(fieldAttrPojo.getDateGroupType());
                }
                headChild.add(pojo);
            });
        }

        //行分组的层级关系设置
        if (CollectionsUtil.isNotEmpty(rowGroupAttrList)) {
            ChartStatisticsPojo rowChartPojo = new ChartStatisticsPojo();
            row2setLevel(rowGroupAttrList, rowChartPojo, 0);
            headChild.add(rowChartPojo);
        } else if (CollectionUtils.isNotEmpty(summaryAttrList)){
            ChartStatisticsPojo pojo = new ChartStatisticsPojo();
            pojo.setKey("");
            pojo.setValue("");
            pojo.setHead(true);
            headChild.add(pojo);
        }
        String redisResult = paasRedisHelper.getValue(RedisPrefixConstant.INDEX_CUSTOM_STATISTIC_RESULT, chartEntity.getCorpid() + "_" + chartEntity.getId());
        // 缓存有值时直接取缓存值
        Boolean exportFlag = chartResultPojo.getExportFlag();
        //只有分页情况走缓存
        if (StringUtil.isNotEmpty(redisResult) && exportFlag == null && pageHelper.getCurrentPageNum() != 1) {
            redisMap = JSONObject.parseObject(redisResult);
        } else {
            JSONObject rowResult = null;
            JSONObject colResult = null;
            JSONObject summaryResult = null;
            EsUtil.parseConditionIntersection(boolQueryBuilder, chartEntity, false);
            customHelp.customIndexQueryDefaultFilter(chartEntity, boolQueryBuilder);

            // 将行和列的所有字段都做exists处理
            boolean isSingle = EsUtil.getSingle(chartEntity);
            for (FieldAttrPojo fieldAttrPojo : groupAttrList) {
                boolean inData = EsUtil.setInData(fieldAttrPojo.getFieldType());
                StringBuilder field = new StringBuilder();
                if (inData && isSingle) {
                    field.append("data.");
                }
                field.append(fieldAttrPojo.getAttr());
                if (EsHelper.isTeamLogicByFieldType(fieldAttrPojo.getFieldType(), fieldAttrPojo.getBusinessType()) && !isSingle) {
                    field = new StringBuilder("myTeamMain_").append(EsUtil.getTeamIdx(chartEntity, fieldAttrPojo.getFormId())).append(".userId");
                }
                boolQueryBuilder.filter(existsQuery(field.toString()));
            }
            Map<String, String> sortMap = chartResultPojo.getSortStatisticsMap();
            if (sortMap == null) {
                JSONObject explains = chartEntity.getExplains();
                if (explains != null) {
                    ExplainsPojo explainsPojo = JSON.parseObject(explains.toJSONString(), ExplainsPojo.class);
                    sortMap = explainsPojo.getSortMap();
                }
            }
            if (CollectionsUtil.isNotEmpty(rowGroupAttrList)) {
                // 行分组查询
                SearchSourceBuilder sourceBuilderRow = new SearchSourceBuilder().query(boolQueryBuilder);
                EsUtil.statisticTableAggregation(sourceBuilderRow, rowGroupAttrList, summaryAttrList, sortMap, chartEntity);
                searchRequest.source(sourceBuilderRow);
                rowResult = xbbElasticsearchRestTemplate.getAggResponseJson(searchRequest).getJSONObject(EsFieldConstant.AGGREGATIONS);
            }

            if (CollectionsUtil.isNotEmpty(colGroupAttrList)) {
                //列分组查询
                SearchSourceBuilder sourceBuilderCol = new SearchSourceBuilder().query(boolQueryBuilder);
                EsUtil.statisticTableAggregation(sourceBuilderCol, colGroupAttrList, summaryAttrList, sortMap, chartEntity);
                searchRequest.source(sourceBuilderCol);
                colResult = xbbElasticsearchRestTemplate.getAggResponseJson(searchRequest).getJSONObject(EsFieldConstant.AGGREGATIONS);
            } else if(CollectionsUtil.isEmpty(colGroupAttrList) && Objects.equals(chartEntity.getSum(), 1)){
                // 无列分组字段且需要总计的时候查询es
                SearchSourceBuilder sourceBuilderSum = new SearchSourceBuilder().query(boolQueryBuilder);
                EsUtil.statisticSummaryAggs(sourceBuilderSum, summaryAttrList, chartEntity);
                searchRequest.source(sourceBuilderSum);
                summaryResult = xbbElasticsearchRestTemplate.getAggResponseJson(searchRequest).getJSONObject(EsFieldConstant.AGGREGATIONS);
            }

            EsUtil.statisticTableAggregation(sourceBuilder,groupAttrList, summaryAttrList, sortMap, chartEntity);
            searchRequest.source(sourceBuilder);
            JSONObject result= xbbElasticsearchRestTemplate.getAggResponseJson(searchRequest).getJSONObject(EsFieldConstant.AGGREGATIONS);

            aggsBucketsMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            // 解析result的数据
            parseGroupData(null, result, groupAttrList, 0, new StringBuilder(""), aggsBucketsMap, summaryAttrMap.keySet());

            // 行列es查询结果集的处理，格式转换
            redisMap = parseStatisticsTable(aggsBucketsMap, pageHelper, chartEntity, rowResult, colResult, exportFlag, summaryAttrMap.keySet(), summaryResult);
        }
        rowIndexResultMap = JSON.parseObject(JSON.toJSONString(redisMap.get("rowIndexResultMap")), new TypeReference<Map<Integer, List<ChartStatisticsPojo>>>(){});
        rowsCount = redisMap.getInteger("rowsCount");
        pageTotal = redisMap.getInteger("pageTotal");
        aggsBucketsMap = JSON.parseObject(JSON.toJSONString(redisMap.get("summaryMap")), new TypeReference<Map<String, Map<String, Object>>>(){});
        body = JSON.parseObject(JSON.toJSONString(redisMap.get("colResultMap")),new TypeReference<List<ChartStatisticsPojo>>(){});
        colTotal = redisMap.getInteger("colTotal");
        summary = redisMap.getJSONArray("summary");

        if (rowIndexResultMap != null) {
            rowDataList = rowIndexResultMap.get(pageHelper.getCurrentPageNum());
        }
        if (summary == null) {
            summary = new JSONArray();
        }
        // 处理数据预警
        Map<String,Object> dwVOMap = chartResultHelp.getDWQueryListVO(chartResultPojo,chartEntity);
        DataWarningQueryListVO dataWarningQueryListVO = (DataWarningQueryListVO) dwVOMap.get("dataWarningQueryListVO");
        // 渲染数据展示
        renderTableData(aggsBucketsMap, summaryAttrMap, rowDataList, body, chartEntity, summary, chartResultPojo,chartResultPojo.getIsWarningSync(),dataWarningQueryListVO);
        if (rowDataList != null) {
            headChild.addAll(rowDataList);
        }

        //添加汇总字段--总计
        if (Objects.equals(chartEntity.getSum(), 1)) {
            // 计算所有汇总字段的汇总和，行汇总和=列汇总和
            /**
             * 先获取每列的总计值，然后根据不同的汇总字段做划分，比如有三个汇总字段，将summaryValueListCopy分成三份，每一份为表单中该汇总字段
             * 的所有值之和，然后将每个数据之和存入总计数组中
             *
             */
            List<String> summaryValueList = JSONArray.parseArray(summary.toJSONString(), String.class);
            List<String> summaryValueListCopy = JSON.parseObject(JSON.toJSONString(CloneUtil.deepClone(summaryValueList)), new TypeReference<List<String>>(){});
            List<String> attrValueList;
            int size = summaryAttrList.size();
            if (CollectionUtils.isNotEmpty(summaryValueList)) {
                for (int i = 0; i < size; i++) {
                    attrValueList = new ArrayList<>();
                    FieldAttrPojo fieldAttrPojo = summaryAttrList.get(i);
                    Integer accuracy = fieldAttrPojo.getAccuracy();
                    accuracy = accuracy == null ? 0 : accuracy;
                    Integer percentUsed = fieldAttrPojo.getPercentUsed();
                    Integer groupingUsed = fieldAttrPojo.getGroupingUsed() == null ? fieldAttrPojo.getAmountFlag() : fieldAttrPojo.getGroupingUsed();
                    String aggType = AggTypeEnum.SUM.getAlias();
                    if (fieldAttrPojo.getAggType() != null) {
                        aggType = fieldAttrPojo.getAggType();
                    }
                    for (int j = 0; j < summaryValueListCopy.size(); j++) {
                        if (j%size == i) {
                            String value = summaryValueList.get(j);
                            if (value.contains("Infinity")) {
                                value = "0.0";
                            }
                            attrValueList.add(value);
                            value = attrDecimalPrecisionHelper.getNumberFormat(value, accuracy, groupingUsed, percentUsed);
                            summaryValueList.set(j, value);
                        }
                    }
                    if (CollectionUtils.isNotEmpty(colGroupAttr)) {
                        String total = getSummaryTotal(attrValueList, aggType);
                        total = attrDecimalPrecisionHelper.getNumberFormat(total, accuracy, groupingUsed, percentUsed);
                        summaryValueList.add(total);
                    }
                }
                table.put("summary", summaryValueList);
            }
        }

        table.put("rowsCount", rowsCount);
        table.put("body", body);
        head.put("child", headChild);
        table.put("head", head);
        table.put("colTotal", colTotal);
        if (Objects.nonNull(dataWarningQueryListVO)){
            table.put("warningFlag",dataWarningQueryListVO.getWarningFlag());
        }else {
            table.put("warningFlag",false);
        }

        pageHelper.setRowsCount(rowsCount);
        if (rowsCount > ChartConstant.MAX_SIZE) {
            pageHelper.setRowsCount(ChartConstant.MAX_SIZE);
        }
        // 如果无行分组字段时，记录条数为列分组的数据总条数
        if (CollectionUtils.isEmpty(rowGroupAttrList)) {
            pageHelper.setRowsCount(colTotal);
        }
        pageHelper.setPageTotal(pageTotal);
        return table;
    }

    /**
     * 将行列分组数据和汇总数据转化成前后端交互的格式，代码很复杂，请细品
     * @param aggsBucketsMap 汇总字段的结果集
     * @param summaryAttrMap  汇总字段类型集合
     * @param rowResultList   行数据
     * @param body      列数据
     * @param chartEntity  图表信息
     * @param summary 总计数组
     * @return void
     */
    private void renderTableData(Map<String, Map<String, Object>> aggsBucketsMap, Map<String, FieldAttrPojo> summaryAttrMap, List<ChartStatisticsPojo> rowResultList, List<ChartStatisticsPojo> body, ChartEntity chartEntity, JSONArray summary, BaseDTO baseDTO, Boolean isWarningSync,DataWarningQueryListVO dataWarningQueryListVO) throws XbbException {
        // 用于计算汇总小计值
        Map<Integer, List<String>> rowKeyMap = new HashMap<>();
        JSONArray rowGroupAttr = chartEntity.getRowGroupAttr();
        JSONArray colGroupAttr = chartEntity.getColGroupAttr();
        List<FieldAttrPojo> rowGroupAttrList = new ArrayList<>();
        List<FieldAttrPojo> colGroupAttrList = new ArrayList<>();
        if (rowGroupAttr != null) {
            rowGroupAttrList = JSONArray.parseArray(rowGroupAttr.toJSONString(), FieldAttrPojo.class);
        }
        if (colGroupAttr != null) {
            colGroupAttrList = JSONArray.parseArray(colGroupAttr.toJSONString(), FieldAttrPojo.class);
        }
        List<Map<String, String>> valueList;
        /**
         * 处理行分组数据，将分组的es数据解析成展示的数据样式
         */
        if (CollectionsUtil.isNotEmpty(rowResultList)) {
            // 移除存在小计的情况
            rowResultList = rowResultList.stream().filter(obj -> !obj.getIsSummary()).collect(Collectors.toList());
            valueList = setEsParseData(rowGroupAttrList, rowResultList, chartEntity, baseDTO,isWarningSync);
            for (int i = 0; i < rowResultList.size(); i++) {
                List<String> rowKeyList = new ArrayList<>();
                int index = 0;
                ChartStatisticsPojo pojo = rowResultList.get(i);
                Map<String, String> map = valueList.get(index);
                pojo.setValue(map.get(pojo.getOriginValue()) == null ? "" : map.get(pojo.getOriginValue()));
                StringBuilder builder = new StringBuilder("[").append(pojo.getOriginValue()).append("]&&");
                if (CollectionUtils.isNotEmpty(pojo.getChild())) {
                    parse2RowKeyList(pojo.getChild(), builder, rowKeyList, valueList, index);
                } else {
                    rowKeyList.add(builder.substring(0,builder.length()-2));
                }
                rowKeyMap.put(i, rowKeyList);
            }
        }

        /**
         * 将列分组的es数据转换成展示的数据样式，主要是处理数据字典的问题
         */
        if (CollectionsUtil.isNotEmpty(body)) {
            valueList = setEsParseData(colGroupAttrList, body, chartEntity, baseDTO,isWarningSync);
            for (ChartStatisticsPojo pojo : body) {
                int index = 0;
                Map<String, String> valueMap = valueList.get(index);
                pojo.setValue(valueMap.get(pojo.getOriginValue()) == null ? "" : valueMap.get(pojo.getOriginValue()));
                StringBuilder builder = new StringBuilder("[").append(pojo.getOriginValue()).append("]&&");
                if (CollectionUtils.isNotEmpty(pojo.getChild())) {
                    obtainBodyData(aggsBucketsMap, summaryAttrMap, rowKeyMap, valueList, index, pojo, builder, chartEntity, summary,dataWarningQueryListVO);
                } else {
                    // 塞入汇总值
                    List<ChartStatisticsPojo> child = new ArrayList<>();
                    setSummaryValue(aggsBucketsMap, summaryAttrMap, chartEntity, rowKeyMap, builder, child, summary,dataWarningQueryListVO);
                    pojo.setChild(child);
                }
            }

            // 列汇总
            if (Objects.equals(chartEntity.getSum(), 1) && CollectionUtils.isNotEmpty(summaryAttrMap.keySet())) {
                // body中添加列分组的总计字段
                ChartStatisticsPojo statisticsPojo = new ChartStatisticsPojo();
                statisticsPojo.setKey("");
                statisticsPojo.setValue(I18nMessageUtil.getMessage(CommonConstant.TOTAL));
                statisticsPojo.setIsSummary(true);
                // 塞入汇总值
                List<ChartStatisticsPojo> child = new ArrayList<>();
                setSummaryValue(aggsBucketsMap, summaryAttrMap, chartEntity, rowKeyMap, new StringBuilder(""), child, null,dataWarningQueryListVO);
                statisticsPojo.setChild(child);
                body.add(statisticsPojo);
            }
        }
        if (CollectionsUtil.isEmpty(colGroupAttrList) && CollectionsUtil.isNotEmpty(rowResultList)) {
            setSummaryValue(aggsBucketsMap, summaryAttrMap, chartEntity, rowKeyMap, new StringBuilder(""), body, summary,dataWarningQueryListVO);
        }
    }

    /**
     * 塞入汇总值
     * @param aggsBucketsMap
     * @param summaryAttrMap
     * @param chartEntity
     * @param rowKeyMap
     * @param builder
     * @param child
     * @param summary
     * @return void
     */
    private void setSummaryValue(Map<String, Map<String, Object>> aggsBucketsMap, Map<String, FieldAttrPojo> summaryAttrMap, ChartEntity chartEntity,
                                 Map<Integer, List<String>> rowKeyMap, StringBuilder builder, List<ChartStatisticsPojo> child, JSONArray summary, DataWarningQueryListVO dataWarningQueryListVO) {
        Integer chartType = chartEntity.getChartType();
        List<FieldAttrPojo> rowAttrPojo = JSON.parseArray(chartEntity.getRowGroupAttr().toJSONString(), FieldAttrPojo.class);
        List<FieldAttrPojo> colAttrPojo = JSON.parseArray(chartEntity.getColGroupAttr().toJSONString(), FieldAttrPojo.class);
        // 获取行、列中的第一个日期字段
        FieldAttrPojo dateFieldAttrPojo = null;
        Boolean isRow = null;
        Integer dateIndex = null;
        for (int i = 0; i < rowAttrPojo.size(); i++) {
            FieldAttrPojo row = rowAttrPojo.get(i);
            if (EsUtil.isDateByEsalias(row)) {
                dateFieldAttrPojo = row;
                isRow = true;
                dateIndex = i;
                break;
            }
        }
        if (dateFieldAttrPojo == null) {
            for (int i = 0; i < colAttrPojo.size(); i++) {
                FieldAttrPojo col = colAttrPojo.get(i);
                if (EsUtil.isDateByEsalias(col)) {
                    dateFieldAttrPojo = col;
                    isRow = false;
                    dateIndex = i;
                    break;
                }
            }
        }
        // 处理汇总
        for (Iterator<Map.Entry<String, FieldAttrPojo>> iterator = summaryAttrMap.entrySet().iterator(); iterator.hasNext(); ) {
            Map.Entry<String, FieldAttrPojo> entry = iterator.next();
            String sumKey = entry.getKey();
            FieldAttrPojo fieldAttrPojo = entry.getValue();
            Integer accuracy = fieldAttrPojo.getAccuracy();
            accuracy = accuracy == null ? 0 : accuracy;
            Integer percentUsed = fieldAttrPojo.getPercentUsed();
            Integer groupingUsed = fieldAttrPojo.getGroupingUsed() == null ? fieldAttrPojo.getAmountFlag() : fieldAttrPojo.getGroupingUsed();
            JSONArray advancedComputing = fieldAttrPojo.getAdvancedComputing();
            // 是否同环比
            boolean isYearChain = chartResultHelp.isYearChain4Date(dateFieldAttrPojo, advancedComputing);
            String aggType = AggTypeEnum.SUM.getAlias();
            if (fieldAttrPojo.getAggType() != null) {
                aggType = fieldAttrPojo.getAggType();
            }
            AggTypeEnum aggTypeEnum = AggTypeEnum.getByAlias(fieldAttrPojo.getAggType());
            ChartStatisticsPojo chartPojo = new ChartStatisticsPojo();
            List<String> values = new ArrayList<>();
            String colKey = StringUtils.isBlank(builder) ? "" : builder.substring(0, builder.length() - 2);
            if (CollectionUtils.isNotEmpty(rowKeyMap.entrySet())) {
                // 判断是汇总小计还是总计还是不汇总
                if (Objects.equals(chartEntity.getSum(), 1) && StringUtils.isNotBlank(colKey)) {
                    // 对汇总结果集进行总计
                    List<String> rowKeyList = new ArrayList<>();
                    rowKeyMap.forEach((k, v) -> rowKeyList.addAll(v));
                    for (String rowKey : rowKeyList) {
                        String scriptKey = rowKey + "&&" + colKey;
                        //塞值
                        Map<String, Object> map = aggsBucketsMap.get(scriptKey);
                        String value = map == null ? "" : (String) map.get(sumKey);
                        // 格式化
                        value = attrDecimalPrecisionHelper.getNumberFormat(value, accuracy, groupingUsed, percentUsed);
                        values.add(value);
                    }

                    Map<String, Object> map = aggsBucketsMap.get(colKey);
                    String total = map == null ? "" : (String) map.get(sumKey);
                    summary.add(total);
                } else if (Objects.equals(chartEntity.getSum(), 1) && StringUtils.isBlank(colKey)) {
                    // 对列分组结果集进行总计
                    List<String> rowKeyList = new ArrayList<>();
                    rowKeyMap.forEach((k, v) -> rowKeyList.addAll(v));
                    for (String rowKey : rowKeyList) {
                        //塞值
                        Map<String, Object> map = aggsBucketsMap.get(rowKey);
                        String value = map == null ? "" : (String) map.get(sumKey);
                        // 格式化
                        value = attrDecimalPrecisionHelper.getNumberFormat(value, accuracy, groupingUsed, percentUsed);
                        values.add(value);
                    }
                } else if (Objects.equals(chartEntity.getSum(), 0) && StringUtils.isNotBlank(colKey)) {
                    // 对汇总结果集进行小计
                    List<String> subTotal;
                    for (Integer i : rowKeyMap.keySet()) {
                        subTotal = new ArrayList<>();
                        List<String> rowKeyList = rowKeyMap.get(i);
                        for (String rowKey : rowKeyList) {
                            String scriptKey = rowKey + "&&" + colKey;
                            //塞值
                            Map<String, Object> map = aggsBucketsMap.get(scriptKey);
                            String value = map == null ? "" : (String) map.get(sumKey);
                            subTotal.add(value);
                            value = attrDecimalPrecisionHelper.getNumberFormat(value, accuracy, groupingUsed, percentUsed);
                            values.add(value);
                        }
                        String total = getSummaryTotal(subTotal, aggType);
                        total = attrDecimalPrecisionHelper.getNumberFormat(total, accuracy, groupingUsed, percentUsed);
                        values.add(total);
                    }
                } else if (Objects.equals(chartEntity.getSum(), 0) && StringUtils.isBlank(colKey)) {
                    // 对汇总结果集进行小计
                    List<String> subTotal;
                    for (Integer i : rowKeyMap.keySet()) {
                        subTotal = new ArrayList<>();
                        List<String> rowKeyList = rowKeyMap.get(i);
                        for (String rowKey : rowKeyList) {
                            //塞值
                            Map<String, Object> map = aggsBucketsMap.get(rowKey);
                            String value = map == null ? "" : (String) map.get(sumKey);
                            subTotal.add(value);
                            value = attrDecimalPrecisionHelper.getNumberFormat(value, accuracy, groupingUsed, percentUsed);
                            values.add(value);
                        }
                        String total = getSummaryTotal(subTotal, aggType);
                        total = attrDecimalPrecisionHelper.getNumberFormat(total, accuracy, groupingUsed, percentUsed);
                        values.add(total);
                    }
                } else if (Objects.equals(chartEntity.getSum(), -1) && StringUtils.isNotBlank(colKey)) {
                    List<String> rowKeyList = new ArrayList<>();
                    rowKeyMap.forEach((k, v) -> rowKeyList.addAll(v));
                    for (String rowKey : rowKeyList) {
                        String scriptKey = rowKey + "&&" + colKey;
                        //塞值
                        Map<String, Object> map = aggsBucketsMap.get(scriptKey);
                        String value = map == null ? "" : (String) map.get(sumKey);
                        // 同环比处理
                        if (isYearChain) {
                            String oldValue = getOldValue4Table(aggsBucketsMap, chartType, dateFieldAttrPojo, isRow, dateIndex, sumKey, advancedComputing, colKey, rowKey);
                            value = chartResultHelp.getYearChainValue(fieldAttrPojo, oldValue, value);
                        }
                        // 格式化
                        value = attrDecimalPrecisionHelper.getNumberFormat(value, accuracy, groupingUsed, percentUsed);
                        values.add(value);
                    }
                } else if (Objects.equals(chartEntity.getSum(), -1) && StringUtils.isBlank(colKey)) {
                    List<String> rowKeyList = new ArrayList<>();
                    rowKeyMap.forEach((k, v) -> rowKeyList.addAll(v));
                    for (String rowKey : rowKeyList) {
                        //塞值
                        Map<String, Object> map = aggsBucketsMap.get(rowKey);
                        String value = map == null ? "" : (String) map.get(sumKey);
                        // 同环比处理
                        if (isYearChain) {
                            String oldValue = getOldValue4Table(aggsBucketsMap, chartType, dateFieldAttrPojo, isRow, dateIndex, sumKey, advancedComputing, colKey, rowKey);
                            value = chartResultHelp.getYearChainValue(fieldAttrPojo, oldValue, value);
                        }
                        // 格式化
                        value = attrDecimalPrecisionHelper.getNumberFormat(value, accuracy, groupingUsed, percentUsed);
                        values.add(value);
                    }
                }
            } else if (CollectionUtils.isEmpty(rowKeyMap.entrySet())) {
                // 无行分组字段的情况
                Map<String, Object> map = aggsBucketsMap.get(colKey);
                String value = map == null ? "" : (String) map.get(sumKey);
                if (Objects.equals(chartEntity.getSum(), 1) && StringUtils.isNotBlank(colKey)) {
                    // 总计
                    summary.add(value);
                } else if (Objects.equals(chartEntity.getSum(), 1) && StringUtils.isBlank(colKey)) {
                    // 得特殊处理，没有行字段，那么列分组的汇总即为aggsBucketsMap中的每个汇总字段之和
                    List<Map<String, Object>> aggsValueList = new ArrayList<>(aggsBucketsMap.values());
                    List<String> colValueList = new ArrayList<>();
                    for (Map<String, Object> objectMap : aggsValueList) {
                        String v = objectMap == null ? "" : (String) objectMap.get(sumKey);
                        colValueList.add(v);
                    }
                    value = getSummaryTotal(colValueList, aggType);
                }
                // 同环比处理
                if (isYearChain) {
                    String oldValue = getOldValue4Table(aggsBucketsMap, chartType, dateFieldAttrPojo, isRow, dateIndex, sumKey, advancedComputing, colKey, "");
                    value = chartResultHelp.getYearChainValue(fieldAttrPojo, oldValue, value);
                }
                // 格式化
                value = attrDecimalPrecisionHelper.getNumberFormat(value, accuracy, groupingUsed, percentUsed);
                values.add(value);
            }
            // 计算字段日期公式特殊显示
            String suffix = "";
            if(Objects.equals(fieldAttrPojo.getFieldType(),FieldTypeEnum.COMPUTED_FIELD.getType())){
                String formula = fieldAttrPojo.getFormulaInfo().getString("formula");
                String formulaName = RegexUtil.extractFormulaName(formula);
                if (Objects.equals(formulaName,"DATE_DIFF")){
                    String unit = DateDiffTypeEnum.DAY.getAlias();
                    String textTemp = formula.substring(1,formula.length()-1);
                    int startIndex;
                    if (textTemp.lastIndexOf("}") < (startIndex = textTemp.lastIndexOf(","))){
                        unit = textTemp.substring(startIndex);
                    }
                    DateDiffTypeEnum typeEnum = DateDiffTypeEnum.getByAlias(unit);
                    suffix = typeEnum.getName();
                }
            }

            chartPojo.setKey(fieldAttrPojo.getAttr());
            chartPojo.setIsLeaf(true);
            if (StringUtil.isNotEmpty(suffix)){
                chartPojo.setValue(fieldAttrPojo.getLabelName() + "(" + suffix + ")");
            }else if (Objects.equals(fieldAttrPojo.getFieldType(),FieldTypeEnum.COMPUTED_FIELD.getType())){
                chartPojo.setValue(fieldAttrPojo.getLabelName());
            }else {
                chartPojo.setValue(fieldAttrPojo.getLabelName() + "(" + aggTypeEnum.getName() + ")");
            }
            chartPojo.setValues(values);
            chartPojo.setFormId(fieldAttrPojo.getFormId());
            // 统计表数据预警start
            List<WarningValuePojo> warningValues = new ArrayList<>();
            String originalAttr = fieldAttrPojo.getOriginalAttr();
            String dwKey = fieldAttrPojo.getAttr() + "&" + fieldAttrPojo.getFormId();
            if (Objects.isNull(fieldAttrPojo.getAttr()) && Objects.nonNull(originalAttr)){
                dwKey = originalAttr + "&" + fieldAttrPojo.getFormId();
            }

            // 为了防止一个当前预警数据同时触发多个预警设置，不知道选那个，取这个预警数据到预警设置最接近的数据
            Map<String,Object> distinctMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            int warningIndex = 0;
            if (Objects.nonNull(dataWarningQueryListVO) && CollectionUtils.isNotEmpty(dataWarningQueryListVO.getDataWarningQueryVOList())){
                for (DataWarningQueryVO item : dataWarningQueryListVO.getDataWarningQueryVOList()) {
                    // 统计表有多值
                    List<DwTriggerConditionPojo> triggerConditionList = item.getTriggerCondition().toJavaList(DwTriggerConditionPojo.class);
                    DwTriggerConditionPojo triggerConditionPojo;
                    if (CollectionUtils.isNotEmpty(triggerConditionList) && Objects.nonNull(sumKey)){
                        triggerConditionPojo = triggerConditionList.get(0);
                        if(!dwKey.contains(triggerConditionPojo.getId())){
                            continue;
                        }
                    }else {
                        continue;
                    }
                    int valueIndex = 0;
                    for (String value : values) {
                        if (chartResultHelp.checkIsTrigger(item.getTriggerCondition(), value)) {
                            WarningValuePojo warningValuePojo = new WarningValuePojo(){{setValue(value);setColor(item.getColor());setWarningFlag(true);}};
                            if (chartResultHelp.isCover(item.getTriggerCondition(), value,distinctMap,valueIndex)){
                                if ((warningValues.size()-1) >= valueIndex){
                                    warningValues.set(valueIndex,warningValuePojo);
                                    dataWarningQueryListVO.setWarningFlag(true);
                                }else {
                                    warningValues.add(warningValuePojo);
                                    dataWarningQueryListVO.setWarningFlag(true);
                                }
                            }else if (warningValues.size() < values.size()){
                                warningValues.add(warningValuePojo);
                                dataWarningQueryListVO.setWarningFlag(true);
                            }
                        }else if (warningIndex == 0){
                            warningValues.add(new WarningValuePojo(){{setValue(value);setWarningFlag(false);}});
                        }
                        valueIndex++;
                    }
                    warningIndex ++;
                }
            }
            chartPojo.setWarningValues(warningValues);
            // 统计表数据预警end

            child.add(chartPojo);
        }
    }

    /**
     * 统计表获取同（环）期值
     * @param aggsBucketsMap
     * @param chartType
     * @param dateFieldAttrPojo
     * @param isRow
     * @param dateIndex
     * @param sumKey
     * @param advancedComputing
     * @param colKey
     * @param rowKey
     * @return java.lang.String
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2021/7/19 19:32
     * @version 1.0
     */
    private String getOldValue4Table(Map<String, Map<String, Object>> aggsBucketsMap, Integer chartType, FieldAttrPojo dateFieldAttrPojo, Boolean isRow, Integer dateIndex, String sumKey, JSONArray advancedComputing, String colKey, String rowKey) {
        String oldValue = "";
        if (Objects.isNull(isRow)) {
            return oldValue;
        }
        if (isRow) {
            // 行字段为日期字段，需要根据日期字段位置进行截取
            List<String> rowList = Arrays.asList(rowKey.split("&&"));
            String dateRow = rowList.get(dateIndex).substring(1, rowList.get(dateIndex).length() - 1);
            Long yearChainDiff = chartResultHelp.getYearChainDiff(chartType, dateFieldAttrPojo, advancedComputing, Long.valueOf(dateRow));
            rowList.set(dateIndex, "[" + yearChainDiff.toString() + "]");
            String oldKey = String.join("&&", rowList);
            oldKey = "".equals(colKey) ? oldKey : oldKey + "&&" + colKey;
            Map<String, Object> oldValueMap = aggsBucketsMap.get(oldKey);
            oldValue = oldValueMap == null ? "" : (String) oldValueMap.get(sumKey);
        } else {
            // 列字段为日期字段，需要根据日期字段位置进行截取
            List<String> colList = Arrays.asList(colKey.split("&&"));
            String dateCol = colList.get(dateIndex).substring(1, colList.get(dateIndex).length() - 1);
            Long yearChainDiff = chartResultHelp.getYearChainDiff(chartType, dateFieldAttrPojo, advancedComputing, Long.valueOf(dateCol));
            colList.set(dateIndex, "[" + yearChainDiff.toString() + "]");
            String oldKey = String.join("&&", colList);
            oldKey = "".equals(rowKey) ? oldKey : rowKey + "&&" + oldKey;
            Map<String, Object> oldValueMap = aggsBucketsMap.get(oldKey);
            oldValue = oldValueMap == null ? "" : (String) oldValueMap.get(sumKey);
        }
        return oldValue;
    }

    /**
     * 获取每个层级分组的所有es数据并转化成展示的数据值
     * @param groupAttrList  分组字段的数组
     * @param resultList  分组数据的结果集
     * @param chartEntity 图表对象
     * @return java.util.List<java.util.Map<java.lang.String,java.lang.String>>
     */
    private List<Map<String, String>> setEsParseData(List<FieldAttrPojo> groupAttrList, List<ChartStatisticsPojo> resultList, ChartEntity chartEntity, BaseDTO baseDTO,Boolean isWarningSync) throws XbbException {
        Map<String, String> resultMap;
        List<Map<String, String>> valueList = new ArrayList<>();
        for (int i = 0; i < groupAttrList.size(); i++) {
            List<String> values = new ArrayList<>();
            values = getOriginValuesList(resultList, i, values);
            FieldAttrPojo fieldAttrPojo = groupAttrList.get(i);
            resultMap = chartResultHelp.valueListAnalysis(fieldAttrPojo, chartEntity.getCorpid(), values, chartEntity, true, null, true, baseDTO,isWarningSync);
            valueList.add(resultMap);
        }
        return valueList;
    }

    /**
     * 获取每个分组层级的所有es存储的数据集合
     * @param resultList
     * @param i
     * @param values
     * @return java.util.List<java.lang.String>
     */
    private List<String> getOriginValuesList(List<ChartStatisticsPojo> resultList, int i, List<String> values) {
        if (i == 0) {
            for (ChartStatisticsPojo pojo : resultList) {
                values.add(pojo.getOriginValue());
            }
        } else {
            i -= 1;
            for (ChartStatisticsPojo pojo : resultList) {
                getOriginValuesList(pojo.getChild(), i, values);
            }
        }
        return values;
    }

    /**
     * 解析行列分组的数据，封装到ChartStatisticsPojo中，并存入redis中
     * @param aggsBucketsMap  汇总结果集
     * @param pageHelper  分页信息
     * @param chartEntity  图表对象
     * @param rowResult   行分组聚合结果集
     * @param colResult   列分组聚合结果集
     * @param exportFlag    是否为导出标识
     * @param summarySet
     * @return com.alibaba.fastjson.JSONObject
     * @author 石安
     * @date 2020-06-16
     */
    private JSONObject parseStatisticsTable(Map<String, Map<String, Object>> aggsBucketsMap, PageHelper pageHelper, ChartEntity chartEntity, JSONObject rowResult,
                                            JSONObject colResult, Boolean exportFlag, Set<String> summarySet, JSONObject summaryResult) {
        int size = 0;
        List<ChartStatisticsPojo> body = new ArrayList<>();
        List<ChartStatisticsPojo> rowResultList = new ArrayList<>();
        JSONArray rowGroupAttr = chartEntity.getRowGroupAttr();
        JSONArray colGroupAttr = chartEntity.getColGroupAttr();
        List<FieldAttrPojo> rowGroupAttrList = new ArrayList<>();
        List<FieldAttrPojo> colGroupAttrList = new ArrayList<>();
        if (rowGroupAttr != null) {
            rowGroupAttrList = JSONArray.parseArray(rowGroupAttr.toJSONString(), FieldAttrPojo.class);
        }
        if (colGroupAttr != null) {
            colGroupAttrList = JSONArray.parseArray(colGroupAttr.toJSONString(), FieldAttrPojo.class);
        }
        // 处理行分组的数据
        parseGroupData(rowResultList, rowResult, rowGroupAttrList, size, new StringBuilder(""), aggsBucketsMap, summarySet);
        // 处理列分组数据
        parseGroupData(body, colResult, colGroupAttrList, size, new StringBuilder(""), aggsBucketsMap, summarySet);

        /**
         * 以第一层分组为基准，当分组下的数据之和未超过 pagesize 时继续添加下一个分组集合，直到刚超过 pagesize 时为一页的数据
         * 举例：以姓名为第一层分组（张三，李四，王五）pagesize = 10，当张三下面的数据有超过10时，以张三分组下的所有结果集为一页数据，如果张三的数据未满10时，添加李四下的数据，直到他们的数据集和超过10才设置为一页数据
         */
        int total = 0;
        int pageCount = 0;
        int index = 1;
        if (exportFlag != null && exportFlag) {
            // 导出时设置最大数量为50000
            pageHelper.setPageSize(50000);
        } else {
            pageHelper.setPageSize(PageHelper.PAGE_SIZE_HALF);
        }
        Map<Integer, List<ChartStatisticsPojo>> rowIndexResultMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<ChartStatisticsPojo> pageList = new ArrayList<>();
        for (ChartStatisticsPojo pojo : rowResultList) {
            if (CollectionUtils.isNotEmpty(pojo.getChild())) {
                pageCount = calculateTotal(pojo.getChild(), pageCount);
            } else {
                pageCount += 1;
            }
            pageList.add(pojo);
            // 是否开启汇总小计
            if (Objects.equals(chartEntity.getSum(), 0) && CollectionUtils.isNotEmpty(summarySet)) {
                ChartStatisticsPojo statisticsPojo = new ChartStatisticsPojo();
                statisticsPojo.setKey("");
                statisticsPojo.setValue(I18nMessageUtil.getMessage(CommonConstant.SUBTOTAL));
                statisticsPojo.setIsSummary(true);
                pageList.add(statisticsPojo);
            }
            if (pageCount >= pageHelper.getPageSize()) {
                total += pageCount;
                pageCount = 0;
                List<ChartStatisticsPojo> pageData = new ArrayList<>(pageList);
                rowIndexResultMap.put(index, pageData);
                index++;
                pageList.clear();
            }
        }

        if (CollectionsUtil.isNotEmpty(pageList)) {
            rowIndexResultMap.put(index, pageList);
            total += pageCount;
        } else {
            if (index != 1) {
                index--;
            }
        }
        // 计算列的数据总条数
        int colTotal = 0;
        for (ChartStatisticsPojo pojo : body) {
            int count = 0;
            if (CollectionUtils.isNotEmpty(pojo.getChild())) {
                count = calculateTotal(pojo.getChild(), count);
            } else {
                count++;
            }
            colTotal += count;
        }

        Map<String, Object> redisMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        redisMap.put("rowIndexResultMap", rowIndexResultMap);
        redisMap.put("rowsCount", total);
        redisMap.put("pageTotal", index);
        redisMap.put("summaryMap", aggsBucketsMap);
        redisMap.put("colResultMap", body);
        redisMap.put("colTotal", colTotal);

        if (summaryResult != null) {
            JSONArray summary = new JSONArray();
            for (String attr : summarySet) {
                summary.add(summaryResult.getJSONObject(attr).getString(EsFieldConstant.VALUE));
            }
            redisMap.put("summary", summary);
        }

        //导出时不更新缓存
        if (exportFlag == null || !exportFlag) {
            String value = paasRedisHelper.getValue(RedisPrefixConstant.BUILD_WARE_FLAG, chartEntity.getCorpid() + "_" + chartEntity.getId());
            // 无查询条件时存缓存
            if (value == null && CollectionsUtil.isEmpty(chartEntity.getSearch())) {
                paasRedisHelper.setValue(RedisPrefixConstant.INDEX_CUSTOM_STATISTIC_RESULT, chartEntity.getCorpid() + "_" + chartEntity.getId(), redisMap, TimeConstant.TINY_DURATION);
            }
        }
        return new JSONObject(redisMap);
    }


    /**
     * 分组数据的数量计算
     * @param child
     * @param pageCount
     * @return void
     */
    private int calculateTotal(List<ChartStatisticsPojo> child, int pageCount) {
        for (ChartStatisticsPojo pojo : child) {
            if (CollectionsUtil.isEmpty(pojo.getChild())) {
                pageCount++;
                continue;
            }
            pageCount = calculateTotal(pojo.getChild(), pageCount);
        }
        return pageCount;
    }

    /**
     * 设置行分组字段的父子层级关系
     * @param rowGroupAttrList
     * @param rowChartPojo
     * @param size
     * @return void
     */
    private void row2setLevel(List<FieldAttrPojo> rowGroupAttrList, ChartStatisticsPojo rowChartPojo, int size) {
        FieldAttrPojo fieldAttrPojo = rowGroupAttrList.get(size);
        String labelName = fieldAttrPojo.getLabelName();
        String label = fieldAttrPojo.getLabel();
        String attrName = fieldAttrPojo.getAttrName();
        rowChartPojo.setKey(fieldAttrPojo.getAttr() + "&" + fieldAttrPojo.getFieldType());
        rowChartPojo.setValue(labelName);
        if (Objects.equals(labelName,label)) {
            if (FieldTypeEnum.SUB_FORM.getType().intValue() == fieldAttrPojo.getFieldType()) {
                rowChartPojo.setValue(attrName);
            } else {
                rowChartPojo.setValue(Arrays.asList(label.split("--")).get(0) + "--" + attrName);
            }
        }
        rowChartPojo.setHead(true);
        rowChartPojo.setFormId(fieldAttrPojo.getFormId());
        if (size < rowGroupAttrList.size() - 1) {
           ChartStatisticsPojo pojo = new ChartStatisticsPojo();
           List<ChartStatisticsPojo> rowChild = new ArrayList<>();
           size++;
           row2setLevel(rowGroupAttrList, pojo,size);
           rowChild.add(pojo);
           rowChartPojo.setChild(rowChild);
       }
        if (fieldAttrPojo.getDateGroupType() != null) {
            rowChartPojo.setDateGroupType(fieldAttrPojo.getDateGroupType());
        }
    }

    /**
     * 查询汇总信息
     * @param aggsBucketsMap 汇总结果集
     * @param summaryAttrMap 汇总字段
     * @param rowKeyMap 行分组结果的key拼接
     * @param valueList
     * @param index
     * @param chartStatisticsPojo
     * @param builder
     * @param chartEntity
     * @param summary
     * @return void
     */
    private void obtainBodyData(Map<String, Map<String, Object>> aggsBucketsMap, Map<String, FieldAttrPojo> summaryAttrMap, Map<Integer, List<String>> rowKeyMap,
                                List<Map<String, String>> valueList, int index, ChartStatisticsPojo chartStatisticsPojo, StringBuilder builder, ChartEntity chartEntity, JSONArray summary,DataWarningQueryListVO dataWarningQueryListVO) {
        for (ChartStatisticsPojo pojo : chartStatisticsPojo.getChild()) {
            index++;
            Map<String, String> valueMap = valueList.get(index);
            pojo.setValue(valueMap.get(pojo.getOriginValue()) == null ? "" : valueMap.get(pojo.getOriginValue()));
            String key = pojo.getOriginValue();
            builder.append("[").append(key).append("]&&");
            obtainBodyData(aggsBucketsMap, summaryAttrMap, rowKeyMap, valueList, index, pojo, builder, chartEntity, summary,dataWarningQueryListVO);
            if (index == valueList.size() - 1) {
                //塞入汇总值
                List<ChartStatisticsPojo> child = new ArrayList<>();
                setSummaryValue(aggsBucketsMap, summaryAttrMap, chartEntity, rowKeyMap, builder, child, summary, dataWarningQueryListVO);
                pojo.setChild(child);
            }
            builder.delete(builder.length()-key.length()-4, builder.length());
            index--;
        }
    }

    /**
     * 根据不同的汇总方式 计算汇总值
     * @param values
     * @param aggType
     * @return java.lang.String
     */
    private String getSummaryTotal(List<String> values, String aggType) {
        String total = "0.0";
        values = values.stream().filter(StringUtil::isNotEmpty).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(values)) {
            return total;
        }
        AggTypeEnum aggTypeEnum = AggTypeEnum.getByAlias(aggType);
        BigDecimal sumDecimal = new BigDecimal(total);
        switch (aggTypeEnum) {
            case MAX:
                total = Collections.max(values);
                break;
            case MIN:
                total = Collections.min(values);
                break;
            case AVG:
                BigDecimal countDecimal = new BigDecimal(values.size());
                for (String value : values) {
                    BigDecimal addDecimal = new BigDecimal(value);
                    sumDecimal = sumDecimal.add(addDecimal);
                }
                total = sumDecimal.divide(countDecimal, 6).toPlainString();
                break;
            case COUNT:
                total = String.valueOf(values.size());
                break;
            case SUM:
            default:
                for (String value : values) {
                    //数据超出 1.7976931348623157E+103088 或者小于 -1.7976931348623157E+103088 的数值都展示成0.0
                    if (value.contains(PaasConstant.ES_INFINITY)) {
                        BigDecimal addDecimal = new BigDecimal("0.0");
                        sumDecimal = sumDecimal.add(addDecimal);
                    }else{
                        BigDecimal addDecimal = new BigDecimal(value);
                        sumDecimal = sumDecimal.add(addDecimal);
                    }
                }
                total = sumDecimal.toPlainString();
                break;
        }
        return total;
    }

    /**
     * 解析行分组数据的节点结构
     * 采用回溯的方式拼接字符串,当遍历到最后一个节点（size=0）时才完成一个key
     * @param child
     * @param builder
     * @param rowKeyList
     * @param valueList
     * @param index
     * @return void
     */
    private void parse2RowKeyList(List<ChartStatisticsPojo> child, StringBuilder builder, List<String> rowKeyList, List<Map<String, String>> valueList, int index) {
        for (ChartStatisticsPojo pojo : child) {
            index++;
            Map<String, String> map = valueList.get(index);
            String value = map.get(pojo.getOriginValue()) == null ? "" : map.get(pojo.getOriginValue());
            pojo.setValue(value);
            String key = pojo.getOriginValue();
            builder.append("[").append(key).append("]&&");
            parse2RowKeyList(pojo.getChild(), builder, rowKeyList, valueList, index);
            if (index == valueList.size() - 1) {
                rowKeyList.add(builder.substring(0,builder.length()-2));
            }
            index--;
            builder.delete(builder.length()-key.length()-4, builder.length());
        }
    }

    /**
     * es查询的分组结果转化
     * 判断当前节点是否是最后的节点，如果是最后节点则不做处理，否则继续遍历，当处理该节点时判断子节点是否有数据，如果无数据则删除该树枝
     * @param child
     * @param rowResult 行分组的es数据
     * @param groupAttrList 分组数组
     * @param size
     * @param key
     * @param aggsBucketsMap 汇总所有结果集
     * @param summarySet
     * @return void
     */
    private void parseGroupData(List<ChartStatisticsPojo> child, JSONObject rowResult, List<FieldAttrPojo> groupAttrList, int size,
                                StringBuilder key, Map<String, Map<String, Object>> aggsBucketsMap, Set<String> summarySet) {
        if(size < groupAttrList.size() && rowResult != null){
            JSONObject result;
            FieldAttrPojo fieldAttrPojo = groupAttrList.get(size);
            String aggName = fieldAttrPojo.getAttr() + "&" + fieldAttrPojo.getFieldType();
            result = rowResult.getJSONObject(aggName);
            if (Objects.nonNull(result)) {
                JSONArray rowArray = result.getJSONArray(EsFieldConstant.BUCKETS);
                if (CollectionsUtil.isNotEmpty(rowArray)) {
                    for (Object object : rowArray) {
                        size++;
                        JSONObject item = (JSONObject) object;
                        String esValue = item.getString(EsFieldConstant.KEY);
                        key.append("[").append(esValue).append("]&&");
                        if (Objects.nonNull(child)) {
                            ChartStatisticsPojo pojo = new ChartStatisticsPojo();
                            pojo.setKey(aggName);
                            pojo.setValue(esValue);
                            pojo.setOriginValue(esValue);
                            pojo.setDocCount(item.getLong(EsFieldConstant.DOC_COUNT));
                            pojo.setChild(new ArrayList<>());
                            child.add(pojo);
                            parseGroupData(pojo.getChild(), item, groupAttrList, size, key, aggsBucketsMap, summarySet);
                        } else {
                            parseGroupData(null, item, groupAttrList, size, key, aggsBucketsMap, summarySet);
                        }
                        if (size == groupAttrList.size()) {
                            // 将行或列分组汇总结果封装
                            Map<String, Object> summaryMap = new HashMap<>(summarySet.size());
                            for (String attr : summarySet) {
                                if (Objects.nonNull(item.getJSONObject(attr))) {
                                    summaryMap.put(attr, item.getJSONObject(attr).getString(EsFieldConstant.VALUE));
                                }
                            }
                            aggsBucketsMap.put(key.substring(0,key.length()-2), summaryMap);
                        }
                        size--;
                        key.delete(key.length()-esValue.length()-4, key.length());
                    }
                }
            }
        }

    }
    /**
     * 图表展示
     *
     * @param chartEntity      图表实体类
     * @param boolQueryBuilder 搜索条件
     * @return JSONObject 结果集
     * @throws XbbException error
     */
    private JSONObject chartsAnalysisByChart(ChartEntity chartEntity, SearchSourceBuilder sourceBuilder, BoolQueryBuilder boolQueryBuilder,
                                             ChartResultPojo chartResultPojo, SearchRequest searchRequest) throws XbbException {
        Aggregations aggregations = null;
        JSONObject result = new JSONObject();
        JSONArray tableHead = new JSONArray();
        boolean hasIntersection;
        //分类 系列字段限制
        if (chartEntity.getChartClassify().size() > 0 && chartEntity.getChartValue().size() > 0) {
            //拼装筛选条件
            hasIntersection = EsUtil.parseConditionIntersection(boolQueryBuilder, chartEntity, false);
            customHelp.customIndexQueryDefaultFilter(chartEntity, boolQueryBuilder);
            Map<String, String> sortMap = getSortMap(chartEntity, chartResultPojo.getSortStatisticsMap());
            //聚合条件组装
            chartAggregationsBuilder(chartEntity, sourceBuilder, sortMap);
            //统计图表不需要返回hits内容
            sourceBuilder.size(0);
            searchRequest.source(sourceBuilder);
            if (hasIntersection) {
                aggregations = xbbElasticsearchRestTemplate.query(searchRequest);
            }
            //返回结果渲染
            result = chartStatistics(chartEntity, tableHead, aggregations, chartResultPojo);
        }
        return result;
    }

    /**
     * 获取排序
     * @param chartEntity
     * @param sortStatisticsMap
     * @return
     */
    private Map<String, String> getSortMap(ChartEntity chartEntity, Map<String, String> sortStatisticsMap) {
        Map<String, String> sortMap = sortStatisticsMap;
        if (sortMap == null) {
            JSONObject explains = chartEntity.getExplains();
            if (explains != null) {
                ExplainsPojo explainsPojo = explains.toJavaObject(ExplainsPojo.class);
                sortMap = explainsPojo.getSortMap();
            }
        }
        return sortMap;
    }

    /**
     * 生日字段特殊处理
     *
     * @param fieldAttrPojo 字段属性
     * @param data          查询结果
     * @param attr          字段attr
     * @return 生日日期
     * @author zhouwq
     * @date 2019/6/3 17:34
     */
    private static String getBirthday(FieldAttrPojo fieldAttrPojo, JSONObject data, String attr) {
        String value = "";
        String linkedText = fieldAttrPojo.getLinkedText();
        String dataValue = data.getString(attr);
        //判断是公历生日或农历生日
        if (Objects.equals(data.getInteger(linkedText), BirthdayTypeEnum.BIRTHDAY.getValue())) {
            value = dataValue;
        } else {
            if (dataValue != null) {
                value = CalendarUtil.lunar2Str(dataValue);
            }
        }
        return value;
    }

    private static String getBirthday(FieldAttrPojo fieldAttrPojo, StatisticBiFormDataEntity statisticPaasFormDataEsEntity, String attr) {
        String value = "";
        Object dataValueObj = ReflectHelper.valueGet(statisticPaasFormDataEsEntity, attr);
        String dataValue = dataValueObj == null ? null : dataValueObj.toString();
        Object birthTypeObj = ReflectHelper.valueGet(statisticPaasFormDataEsEntity, fieldAttrPojo.getLinkedText());
        Integer birthType = birthTypeObj == null ? null : birthTypeObj instanceof Double ? ((Double) birthTypeObj).intValue() : (Integer) birthTypeObj;
        //判断是公历生日或农历生日
        if (Objects.equals(birthType, BirthdayTypeEnum.BIRTHDAY.getValue())) {
            value = dataValue;
        } else {
            if (dataValue != null) {
                value = CalendarUtil.lunar2Str(dataValue);
            }
        }
        return value;
    }

    /**
     * 特殊字段 展示标题处理
     *
     * @param fieldAttrPojo 字段属性详情
     * @param fieldsList    展示字段
     * @param headName      回显标题属性值
     * @param isSingle    是否为单表
     * @param chartEntity   图表实体
     * @author zhouwq
     * @date 2019/6/3 17:25
     */
    private static void specialTableTitleHandle(FieldAttrPojo fieldAttrPojo, List<String> fieldsList, JSONObject headName, Boolean isSingle, ChartEntity chartEntity) {
        Integer fieldType = fieldAttrPojo.getFieldType();
        //生日字段处理
        if (FieldTypeEnum.BIRTHDAY.getType().equals(fieldType)) {
            String linkedText = fieldAttrPojo.getLinkedText();
            fieldsList.add(isSingle ? "data." + linkedText : linkedText);
        } else if (FieldTypeEnum.isSubFormType(fieldType)) {
            SubFormPoJo subFormPoJo = fieldAttrPojo.getSubForm();
            String str = JSONArray.toJSONString(subFormPoJo.getItems(), SerializerFeature.DisableCircularReferenceDetect);
            List<FieldAttrPojo> subFormAttrs = JSONArray.parseArray(str, FieldAttrPojo.class);
            List<JSONObject> subFormItems = new ArrayList<>();
            subFormAttrs.forEach(field -> {
                String attr = field.getAttr();
                JSONObject subFormObj = new JSONObject();
                String parentStr;
                String childStr;
                if (Objects.equals(fieldAttrPojo.getLabelName(),fieldAttrPojo.getLabel())){
                    parentStr = fieldAttrPojo.getAttrName();
                }else{
                    parentStr = fieldAttrPojo.getLabelName();
                }
                if (Objects.equals(field.getLabelName(),field.getLabel())){
                    childStr = field.getAttrName();
                }else{
                    childStr = field.getLabelName();
                }
                AggTypeEnum aggTypeEnum = AggTypeEnum.getByAlias(field.getAggType());
                if (Objects.isNull(field.getAggType())) {
                    subFormObj.put("name", parentStr + "--" + childStr);
                }else{
                    subFormObj.put("name", parentStr + "--" + childStr + "(" + aggTypeEnum.getName() + ")");
                }
                subFormObj.put("key", attr + "&" + field.getFieldType());
                subFormObj.put("formId", fieldAttrPojo.getFormId());
                subFormObj.put("fieldType", field.getFieldType());
                subFormItems.add(subFormObj);
            });
            headName.put("items", subFormItems);
        } else if (FieldTypeEnum.OWNERID.getType().equals(fieldType) || FieldTypeEnum.COUSERID.getType().equals(fieldType)) {
            Long formId = fieldAttrPojo.getFormId();
            if (!isSingle) {
                int teamIdx = EsUtil.getTeamIdx(chartEntity, formId);
                fieldsList.add("myTeamMain_" + teamIdx);
                fieldsList.add("myTeam_" + teamIdx);
            }
        }else if (FieldTypeEnum.COMPUTED_FIELD.getType().equals(fieldType)) {
            String formula = fieldAttrPojo.getFormulaInfo().getString("formula");
            String formulaName = RegexUtil.extractFormulaName(formula);
            if (Objects.equals(formulaName,"DATE_DIFF")){
                String unit = DateDiffTypeEnum.DAY.getAlias();
                String textTemp = formula.substring(1,formula.length()-1);
                int startIndex;
                if (textTemp.lastIndexOf("}") < (startIndex = textTemp.lastIndexOf(","))){
                    unit = textTemp.substring(startIndex + 1).replaceAll("\"","");
                }
                DateDiffTypeEnum typeEnum = DateDiffTypeEnum.getByAlias(unit);
                String suffix = typeEnum.getName();
                headName.put("name",headName.getString("name") + "("+ suffix + ")");
            }
        }
    }

    /**
     * 处理多表情况下的团队字段回显
     *
     * @param values                        回显字段集合
     * @param chartEntity                   图表信息
     * @param formId                        表单模板ID
     * @param statisticPaasFormDataEsEntity ES查询结果
     * @param isMainTeamType                是否为负责人
     * @author zhouwq
     * @date 2020/5/14 15:56
     */
    private static void processTeamField(List<String> values, ChartEntity chartEntity, Long formId, StatisticBiFormDataEntity statisticPaasFormDataEsEntity, boolean isMainTeamType) {
        int teamIdx = EsUtil.getTeamIdx(chartEntity, formId);
        String teamAttr = "myTeam_" + teamIdx;
        Object outData = ReflectHelper.valueGet(statisticPaasFormDataEsEntity, teamAttr);
        Integer isMain = isMainTeamType ? 1 : 0;
        if (outData == null) {
            values.add("");
            return;
        }
        JSONArray teamArray = (JSONArray) outData;
        StringBuilder value = new StringBuilder();
        for (int y = 0; y < teamArray.size(); y++) {
            JSONObject teamObj = teamArray.getJSONObject(y);
            BiUserTeamEntity biUserTeamEntity = JSON.parseObject(teamObj.toJSONString(), BiUserTeamEntity.class);
            if (Objects.equals(biUserTeamEntity.getIsMain(), isMain) && Objects.equals(biUserTeamEntity.getDel(), DelEnum.NORMAL.getDel())) {
                value.append(biUserTeamEntity.getUserName()).append(StringConstant.COMMA);
            }
        }
        if (value.length() == 0) {
            values.add("");
        } else {
            values.add(value.substring(0, value.length() - 1));
        }
    }

    /**
     * 时间格式处理
     * @param timeIndexMapping 时间类型字段对应的分组字段集合下标mapping
     * @param key 字段key值
     * @param item 数据对象
     * @return key
     * @author zhouwq
     * @date 2020/6/19 14:34
     */
    private static String statisticsTimeHandle(Map<Integer, FieldAttrPojo> timeIndexMapping, String key, JSONObject item) {
        String[] keyArray = key.split("&&");
        //时间分组处理，格式化对应时间
        if (timeIndexMapping.size() > 0) {
            timeIndexMapping.forEach((index, field) -> {
                String dateValue = keyArray[index].replaceAll("\\[", "").replaceAll("]", "");
                long formatTime = DateUtil.getTimeByIntervalType(field.getDateGroupType(), dateValue);
                keyArray[index] = "[" + formatTime + "]";
            });
            StringBuilder str = new StringBuilder();
            for (String s : keyArray) {
                str.append(s).append("&&");
            }
            key = str.substring(0, str.length() - 2);
            item.put(EsFieldConstant.KEY, key);
        }
        return key;
    }


    /**
     * 过滤不在chart所有类型字段中的查询条件
     * @param jsonArray chart所有类型字段集合
     * @param searchList 查询条件
     * @author zhouwq
     * @date 2020/12/10 15:15
     */
    private static void existSearchField(JSONArray jsonArray, List<JSONObject> searchList) {
        List<JSONObject> list = jsonArray.toJavaList(JSONObject.class);
        Map<String, JSONObject> keyToFieldObject = new HashMap<>();
        for (JSONObject item : list) {
            if (item != null) {
                String attr = item.getString("attr");
                Integer fieldType = item.getInteger("fieldType");
                //地址字段处理
                if (Objects.equals(fieldType, FieldTypeEnum.ADDRESS.getType()) && attr.contains(StringConstant.POINT)) {
                    attr = attr.split("\\.")[0];
                }
                keyToFieldObject.putIfAbsent(attr + "_" + item.getLong("formId"), item);
            }
        }
        if (searchList != null) {
            searchList.removeIf(obj -> {
                String attr = obj.getString("attr");
                //不为空为子表单字段
                if (Objects.equals(obj.getInteger("fieldType"), FieldTypeEnum.ADDRESS.getType()) && attr.contains(StringConstant.POINT)) {
                    attr = attr.split("\\.")[0];
                } else {
                    String parentAttr = obj.getString("parentAttr");
                    attr = StringUtil.isNotEmpty(parentAttr) ? parentAttr : attr;
                }
                String key = attr + "_" + obj.getLong("formId");
                return !keyToFieldObject.containsKey(key);
            });
        }
    }

    /**
     * 系统图表排序
     * @param chartEntity
     * @param chartResultPojo
     * @param chartResultDetailVO
     */
    private static void sortSystemChart(ChartEntity chartEntity, ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) {
        Boolean noNeedSortMap = (Boolean) ThreadLocalUtil.getValue(ChartCommonConstant.NO_NEED_SORT_MAP_KEY);
        if (noNeedSortMap != null && noNeedSortMap) {
            // 标记无需排序的，直接返回
            ThreadLocalUtil.remove();
            return;
        }
        ThreadLocalUtil.remove();
        JSONObject explains = chartEntity.getExplains() == null ? new JSONObject() : chartEntity.getExplains();
        Boolean changeLess =  explains.getBoolean("changeless");
        Map<String, String> sortMap = null;
        if (changeLess != null && changeLess) {
            sortMap = (Map) explains.get("sortMap");
        }
        sortMap = (chartResultPojo.getSortMap() == null || chartResultPojo.getSortMap().size() == 0) ? sortMap : chartResultPojo.getSortMap();
        if (sortMap == null || sortMap.size() == 0) {
            return;
        }
        List<ResultChartVO> chart = chartResultDetailVO.getChart();
        Integer chartType = null;
        ResultTableVO table = chartResultDetailVO.getTable();
        Map<Integer, Integer> indexMap = new HashMap<>(1 << 4);
        //sortMap在系统表中的场景sortMap.size只可能为1
        for (Map.Entry<String, String> entry : sortMap.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            if (chart != null) {
                for (ResultChartVO o : chart) {
                    chartType = o.getChartType();
                    if (Objects.equals(chartType, ChartTypeEnum.PIE_RING.getCode()) || Objects.equals(chartType, ChartTypeEnum.PIE_CHART.getCode())) {
                        int idx = o.getName().indexOf(key);
                        if (idx == -1) {
                            continue;
                        }
                        List<ResultDataSeriesChartVO> dataSeries = o.getDataSeries();
                        Map<Integer, ResultDataSeriesChartVO> oldIndexMap = new HashMap<>(1 << 4);
                        for (int i = 0; i < dataSeries.size(); i++) {
                            oldIndexMap.put(i, dataSeries.get(i));
                        }
                        List<Map.Entry<Integer, ResultDataSeriesChartVO>> list = new ArrayList<>(oldIndexMap.entrySet());
                        if (Objects.equals(value, "asc")) {
                            list.sort((o1, o2) -> {
                                String o1Str = o1.getValue().getValue();
                                String o2Str = o2.getValue().getValue();
                                boolean o1IsEmpty = Objects.equals(o1Str, "") || Objects.equals(o1Str, "-") || Objects.equals(o1Str, null);
                                boolean o2IsEmpty = Objects.equals(o2Str, "") || Objects.equals(o2Str, "-") || Objects.equals(o2Str, null);
                                if (o1IsEmpty) {
                                    o1Str = "0";
                                }
                                if (o2IsEmpty){
                                    o2Str = "0";
                                }
                                Double o1Int;
                                Double o2Int;
                                try {
                                    o1Int = Double.valueOf(o1Str.replaceAll("%", "").replaceAll(",", ""));
                                    o2Int = Double.valueOf(o2Str.replaceAll("%", "").replaceAll(",", ""));
                                } catch (Exception e) {
                                    //排序异常直接返回原始顺序
                                    return 0;
                                }
                                if (o1Int - o2Int > 0) {
                                    return 1;
                                } else if (o1Int - o2Int == 0) {
                                    return 0;
                                } else {
                                    return -1;
                                }
                            });
                        } else if (Objects.equals(value, "desc")) {
                            list.sort((o1, o2) -> {
                                String o1Str = o1.getValue().getValue();
                                String o2Str = o2.getValue().getValue();
                                boolean o1IsEmpty = Objects.equals(o1Str, "") || Objects.equals(o1Str, "-") || Objects.equals(o1Str, null);
                                boolean o2IsEmpty = Objects.equals(o2Str, "") || Objects.equals(o2Str, "-") || Objects.equals(o2Str, null);
                                if (o1IsEmpty) {
                                    o1Str = "0";
                                }
                                if (o2IsEmpty){
                                    o2Str = "0";
                                }
                                Double o1Int;
                                Double o2Int;
                                try {
                                    o1Int = Double.valueOf(o1Str.replaceAll("%", "").replaceAll(",", ""));
                                    o2Int = Double.valueOf(o2Str.replaceAll("%", "").replaceAll(",", ""));
                                } catch (Exception e) {
                                    //排序异常直接返回原始顺序
                                    return 0;
                                }
                                if (o2Int - o1Int > 0) {
                                    return 1;
                                } else if (o2Int - o1Int == 0) {
                                    return 0;
                                } else {
                                    return -1;
                                }
                            });
                        } else {
                            continue;
                        }
                        //排序前后ID顺序映射关系
                        for (int i = 0; i < list.size(); i++) {
                            indexMap.put(i, list.get(i).getKey());
                        }
                        List<ResultDataSeriesChartVO> newDataSeries = new ArrayList<>();
                        List<String> legend = o.getLegend();
                        List<String> newLegend = new ArrayList<>();
                        indexMap.forEach((idx1, idx2) -> {
                            newDataSeries.add(idx1, dataSeries.get(idx2));
                            newLegend.add(idx1, legend.get(idx2));
                        });
                        o.setDataSeries(newDataSeries);
                        o.setLegend(newLegend);
                    } else if (Objects.equals(chartType, ChartTypeEnum.BAR_CHART.getCode()) || Objects.equals(chartType, ChartTypeEnum.LINE_CHART.getCode()) ||
                            Objects.equals(chartType, ChartTypeEnum.AREA_CHART.getCode()) || Objects.equals(chartType, ChartTypeEnum.RADAR_CHART.getCode())) {
                        int idx = o.getLegend().indexOf(key);
                        if (idx == -1) {
                            continue;
                        }
                        List<ResultDataChartVO> dataChartList = o.getData();
                        ResultDataChartVO resultDataChartVO = o.getData().get(idx);
                        JSONArray json = resultDataChartVO.getValue();
                        List<Object> jsonObjectList = json.toJavaList(Object.class);
                        Map<Integer, Object> oldIndexMap = new HashMap<>(1 << 4);
                        for (int i = 0; i < jsonObjectList.size(); i++) {
                            oldIndexMap.put(i, jsonObjectList.get(i));
                        }
                        List<Map.Entry<Integer, Object>> list = new ArrayList<>(oldIndexMap.entrySet());
                        if (Objects.equals(value, "asc")) {
                            list.sort((o1, o2) -> {
                                String o1Str = o1.getValue().toString();
                                String o2Str = o2.getValue().toString();
                                boolean o1IsEmpty = Objects.equals(o1Str, "") || Objects.equals(o1Str, "-") || Objects.equals(o1Str, null);
                                boolean o2IsEmpty = Objects.equals(o2Str, "") || Objects.equals(o2Str, "-") || Objects.equals(o2Str, null);
                                if (o1IsEmpty) {
                                    o1Str = "0";
                                }
                                if (o2IsEmpty){
                                    o2Str = "0";
                                }
                                Double o1Int;
                                Double o2Int;
                                try {
                                    o1Int = Double.valueOf(o1Str.replaceAll("%", "").replaceAll(",", ""));
                                    o2Int = Double.valueOf(o2Str.replaceAll("%", "").replaceAll(",", ""));
                                } catch (Exception e) {
                                    //排序异常直接返回原始顺序
                                    return 0;
                                }
                                if (o1Int - o2Int > 0) {
                                    return 1;
                                } else if (o1Int - o2Int == 0) {
                                    return 0;
                                } else {
                                    return -1;
                                }
                            });
                        } else if (Objects.equals(value, "desc")) {
                            list.sort((o1, o2) -> {
                                String o1Str = o1.getValue().toString();
                                String o2Str = o2.getValue().toString();
                                boolean o1IsEmpty = Objects.equals(o1Str, "") || Objects.equals(o1Str, "-") || Objects.equals(o1Str, null);
                                boolean o2IsEmpty = Objects.equals(o2Str, "") || Objects.equals(o2Str, "-") || Objects.equals(o2Str, null);
                                if (o1IsEmpty) {
                                    o1Str = "0";
                                }
                                if (o2IsEmpty){
                                    o2Str = "0";
                                }
                                Double o1Int;
                                Double o2Int;
                                try {
                                    o1Int = Double.valueOf(o1Str.replaceAll("%", "").replaceAll(",", ""));
                                    o2Int = Double.valueOf(o2Str.replaceAll("%", "").replaceAll(",", ""));
                                } catch (Exception e) {
                                    //排序异常直接返回原始顺序
                                    return 0;
                                }
                                if (o2Int - o1Int > 0) {
                                    return 1;
                                } else if (o2Int - o1Int == 0) {
                                    return 0;
                                } else {
                                    return -1;
                                }
                            });
                        } else {
                            continue;
                        }
                        //排序前后ID顺序映射关系
                        for (int i = 0; i < list.size(); i++) {
                            indexMap.put(i, list.get(i).getKey());
                        }
                        List<String> xAxis = o.getXAxis();
                        List<String> newXAxis = new ArrayList<>();
                        indexMap.forEach((idx1, idx2) -> newXAxis.add(idx1, xAxis.get(idx2)));
                        dataChartList.forEach(entity -> {
                            JSONArray array = entity.getValue();
                            JSONArray newArray = new JSONArray();
                            indexMap.forEach((idx1, idx2) -> newArray.add(idx1, array.get(idx2)));
                            entity.setValue(newArray);
                        });
                        o.setXAxis(newXAxis);
                    } else if (Objects.equals(chartType, ChartTypeEnum.FUNNEL_COMMON.getCode()) || Objects.equals(chartType, ChartTypeEnum.FUNNEL_COMPLEX.getCode())) {
                        List<TitleRightPojo> title = table.getTitle();
                        int idx;
                        for (idx = 0; idx < title.size(); idx++) {
                            if (Objects.equals(title.get(idx).getTitleValue(), key)) {
                                break;
                            }
                        }
                        if (idx >= title.size()) {
                            continue;
                        }
                        List<List<ResultDataTableVO>> dataList = table.getData();
                        if (dataList == null || dataList.size() == 0) {
                            dataList = table.getMarketData();
                        }
                        Map<Integer, List<ResultDataTableVO>> oldIndexMap = new HashMap<>(1 << 4);
                        for (int i = 0, dataListSize = dataList.size(); i < dataListSize; i++) {
                            oldIndexMap.put(i, dataList.get(i));
                        }
                        List<Map.Entry<Integer, List<ResultDataTableVO>>> list = new ArrayList<>(oldIndexMap.entrySet());
                        if (Objects.equals(value, "asc")) {
                            int finalIdx = idx;
                            list.sort((o1, o2) -> {
                                String o1Str = o1.getValue().get(finalIdx).getValue();
                                String o2Str = o2.getValue().get(finalIdx).getValue();
                                boolean o1IsEmpty = Objects.equals(o1Str, "") || Objects.equals(o1Str, "-") || Objects.equals(o1Str, null);
                                boolean o2IsEmpty = Objects.equals(o2Str, "") || Objects.equals(o2Str, "-") || Objects.equals(o2Str, null);
                                if (o1IsEmpty) {
                                    o1Str = "0";
                                }
                                if (o2IsEmpty){
                                    o2Str = "0";
                                }
                                Double o1Int;
                                Double o2Int;
                                try {
                                    o1Int = Double.valueOf(o1Str.replaceAll("%", "").replaceAll(",", ""));
                                    o2Int = Double.valueOf(o2Str.replaceAll("%", "").replaceAll(",", ""));
                                } catch (Exception e) {
                                    //排序异常直接返回原始顺序
                                    return 0;
                                }
                                if (o1Int - o2Int > 0) {
                                    return 1;
                                } else if (o1Int - o2Int == 0) {
                                    return 0;
                                } else {
                                    return -1;
                                }
                            });
                        } else if (Objects.equals(value, "desc")) {
                            int finalIdx1 = idx;
                            list.sort((o1, o2) -> {
                                String o1Str = o1.getValue().get(finalIdx1).getValue();
                                String o2Str = o2.getValue().get(finalIdx1).getValue();
                                boolean o1IsEmpty = Objects.equals(o1Str, "") || Objects.equals(o1Str, "-") || Objects.equals(o1Str, null);
                                boolean o2IsEmpty = Objects.equals(o2Str, "") || Objects.equals(o2Str, "-") || Objects.equals(o2Str, null);
                                if (o1IsEmpty) {
                                    o1Str = "0";
                                }
                                if (o2IsEmpty){
                                    o2Str = "0";
                                }
                                Double o1Int;
                                Double o2Int;
                                try {
                                    o1Int = Double.valueOf(o1Str.replaceAll("%", "").replaceAll(",", ""));
                                    o2Int = Double.valueOf(o2Str.replaceAll("%", "").replaceAll(",", ""));
                                } catch (Exception e) {
                                    //排序异常直接返回原始顺序
                                    return 0;
                                }
                                if (o2Int - o1Int > 0) {
                                    return 1;
                                } else if (o2Int - o1Int == 0) {
                                    return 0;
                                } else {
                                    return -1;
                                }
                            });
                        } else {
                            continue;
                        }
                        //排序前后ID顺序映射关系
                        for (int i = 0; i < list.size(); i++) {
                            indexMap.put(i, list.get(i).getKey());
                        }
                        List<List<ResultDataTableVO>> newDataList = new ArrayList<>();
                        for (Map.Entry<Integer, Integer> e : indexMap.entrySet()) {
                            Integer idx1 = e.getKey();
                            Integer idx2 = e.getValue();
                            newDataList.add(idx1, dataList.get(idx2));
                        }
                        table.setData(newDataList);
                    }
                }
                if (table != null && indexMap.size() > 0 && (!Objects.equals(chartType, ChartTypeEnum.FUNNEL_COMMON.getCode()) && !Objects.equals(chartType, ChartTypeEnum.FUNNEL_COMPLEX.getCode())) && !Objects.equals(chartResultPojo.getSystemCodeEnum(), SystemCodeEnum.RECEIPT_PRODUCT)) {
                    List<TitleRightPojo> title = table.getTitle();
                    List<TitleRightPojo> newTitle = new ArrayList<>();
                    newTitle.add(title.get(0));
                    indexMap.forEach((idx1, idx2) -> newTitle.add(idx1 + 1, title.get(idx2 + 1)));
                    table.setTitle(newTitle);
                    List<List<ResultDataTableVO>> dataList = table.getData();
                    List<List<ResultDataTableVO>> newDataList = new ArrayList<>();
                    dataList.forEach(e -> {
                        List<ResultDataTableVO> newDataTable = new ArrayList<>();
                        newDataTable.add(e.get(0));
                        indexMap.forEach((idx1, idx2) -> newDataTable.add(idx1 + 1, e.get(idx2 + 1)));
                        newDataList.add(newDataTable);
                    });
                    table.setData(newDataList);
                }
            } else if (table != null) {
                tableReSort(table, key, value, indexMap);
            }
        }


    }

    private static void tableReSort(ResultTableVO table, String key, String value, Map<Integer, Integer> indexMap) {

        List<TitleRightPojo> title = table.getTitle();
        int idx;
        for (idx = 0; idx < title.size(); idx++) {
            if (Objects.equals(title.get(idx).getTitleValue(), key)) {
                break;
            }
        }
        if (idx >= title.size()) {
            return;
        }
        //dataList为空说明为市场活动图表，取的是MarketData
        List<List<ResultDataTableVO>> dataList = (table.getData() == null ?table.getMarketData():table.getData());
        Map<Integer, List<ResultDataTableVO>> oldIndexMap = new HashMap<>(1 << 4);
        for (int i = 0, dataListSize = dataList.size(); i < dataListSize; i++) {
            oldIndexMap.put(i, dataList.get(i));
        }
        List<Map.Entry<Integer, List<ResultDataTableVO>>> list = new ArrayList<>(oldIndexMap.entrySet());
        if (Objects.equals(value, "asc")) {
            int finalIdx = idx;
            list.sort((o1, o2) -> {
                String o1Str = o1.getValue().get(finalIdx).getValue();
                String o2Str = o2.getValue().get(finalIdx).getValue();
                boolean o1IsEmpty = Objects.equals(o1Str, "") || Objects.equals(o1Str, "-") || Objects.equals(o1Str, null);
                boolean o2IsEmpty = Objects.equals(o2Str, "") || Objects.equals(o2Str, "-") || Objects.equals(o2Str, null);
                if (o1IsEmpty) {
                    o1Str = "0";
                }
                if (o2IsEmpty){
                    o2Str = "0";
                }
                Double o1Int;
                Double o2Int;
                try {
                    o1Int = Double.valueOf(o1Str.replaceAll("%", "").replaceAll(",", ""));
                    o2Int = Double.valueOf(o2Str.replaceAll("%", "").replaceAll(",", ""));
                } catch (Exception e) {
                    //排序异常直接返回原始顺序
                    return 0;
                }
                if (o1Int - o2Int > 0) {
                    return 1;
                } else if (o1Int - o2Int == 0) {
                    return 0;
                } else {
                    return -1;
                }
            });
        } else if (Objects.equals(value, "desc")) {
            int finalIdx1 = idx;
            list.sort((o1, o2) -> {
                String o1Str = o1.getValue().get(finalIdx1).getValue();
                String o2Str = o2.getValue().get(finalIdx1).getValue();
                boolean o1IsEmpty = Objects.equals(o1Str, "") || Objects.equals(o1Str, "-") || Objects.equals(o1Str, null);
                boolean o2IsEmpty = Objects.equals(o2Str, "") || Objects.equals(o2Str, "-") || Objects.equals(o2Str, null);
                if (o1IsEmpty) {
                    o1Str = "0";
                }
                if (o2IsEmpty){
                    o2Str = "0";
                }
                Double o1Int;
                Double o2Int;
                try {
                    o1Int = Double.valueOf(o1Str.replaceAll("%", "").replaceAll(",", ""));
                    o2Int = Double.valueOf(o2Str.replaceAll("%", "").replaceAll(",", ""));
                } catch (Exception e) {
                    //排序异常直接返回原始顺序
                    return 0;
                }
                if (o2Int - o1Int > 0) {
                    return 1;
                } else if (o2Int - o1Int == 0) {
                    return 0;
                } else {
                    return -1;
                }
            });
        } else {
            return;
        }
        //排序前后ID顺序映射关系
        for (int i = 0; i < list.size(); i++) {
            indexMap.put(i, list.get(i).getKey());
        }
        List<List<ResultDataTableVO>> newDataList = new ArrayList<>();
        indexMap.forEach((idx1, idx2) -> newDataList.add(idx1, dataList.get(idx2)));
        table.setData(newDataList);
    }

    /**
     * 获取最后一次触发预警业务的时间
     * @return
     */
    long getLeastTriggerTime(){
        // 获取最近一次预警业务触发时间 start
        long dwTriggerTime = 0;
        String key = CompanyConfigEnum.DW_TRIGGER_TIME.getAlias();
        String configValue = paasRedisHelper.getValue(RedisConstant.KEY_COMPANY_CONFIG, key);
        if (Objects.isNull(configValue)) {
            try {
                CompanyConfigEntity companyConfigEntity = companyConfigModel.getByConfigAlias(PaasConstant.DEFAULT_DATA_CORPID, "1");
                if (Objects.isNull(companyConfigEntity)) {
                    CompanyConfigEnum companyConfigEnum = CompanyConfigEnum.getByAlias(PaasConstant.DEFAULT_DATA_CORPID);
                    configValue = companyConfigEnum.getValue();
                } else {
                    configValue = companyConfigEntity.getConfigValue();
                }
                dwTriggerTime = Long.parseLong(configValue);
            } catch (Exception e) {
                LOG.error("getCompanyConfigSetValue error", e);
            }
            paasRedisHelper.setValue(RedisConstant.KEY_COMPANY_CONFIG, key, configValue, TimeConstant.SECONDS_TWO_HOUR);
        }
        // 获取最近一次预警业务触发时间 end
        return dwTriggerTime;
    }

    /**
     * 同（环）期值计算——指标图
     * @param rowGroupAttr
     * @param advancedComputing
     * @param sumKey
     * @param chartType
     * @param chartStatisticsPojoList
     * @param index
     * @param chartStatisticsPojo
     * @return java.lang.String
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2021/7/20 17:18
     * @version 1.0
     */
    private String getOldValue4Target(FieldAttrPojo rowGroupAttr, JSONArray advancedComputing, String sumKey, Integer chartType, List<LinkedHashMap<String, ChartStatisticsPojo>> chartStatisticsPojoList, int index, ChartStatisticsPojo chartStatisticsPojo) {
        String oldVal = "";
        try {
            // 获取相差的桶数
            int yearChainDiff = chartResultHelp.getYearChainDiff(chartType, rowGroupAttr, advancedComputing, Long.parseLong(chartStatisticsPojo.getValue())).intValue();
            if (yearChainDiff > 0) {
                int diffIndex = index - yearChainDiff;
                ChartStatisticsPojo diffObj = null;
                try {
                    diffObj = chartStatisticsPojoList.get(diffIndex).get(sumKey);
                } catch (IndexOutOfBoundsException e) {
                    // 走到这，代表不存在差值，oldVal保持为""即可
                }
                if (Objects.nonNull(diffObj)) {
                    oldVal = diffObj.getOriginValue();
                }
            }
        } catch (Exception e) {
            LOG.error("指标图同环比计算出错:", e);
        }
        return oldVal;
    }

    /**
     * 递归解析 attrMap 对字段进行解析（统计表）
     *
     * @param pageList     数据列表
     * @param parseAttrMap 　表头字段对应需要解析的字段
     * @param chartEntity  图表信息
     */
    private void parseAttrMap(List<Map<String, ChartStatisticsPojo>> pageList, Map<JSONObject, FieldAttrPojo> parseAttrMap, Map<String, FieldAttrPojo> summaryAttrMap, ChartEntity chartEntity, BaseDTO baseDTO) {
        List<Map<String, ChartStatisticsPojo>> mapList = new ArrayList<>();
        Map<String, String> parseMap = null;
        ChartStatisticsPojo chartStatisticsPojo;
        List<String> valueList = new ArrayList<>();
        if (pageList == null) {
            return;
        }
        // 统计字段映射列表
        List<Map<String, ChartStatisticsPojo>> summaryMapList = new ArrayList<>();
        for (int i = 0; i < pageList.size(); i++) {
            Map<String, ChartStatisticsPojo> map = pageList.get(i);
            Iterator<Map.Entry<String, ChartStatisticsPojo>> iterator = map.entrySet().iterator();
            Integer fieldType = null;
            //TODO 待优化 暂无好的优化方案
            while (iterator.hasNext()) {
                Map.Entry<String, ChartStatisticsPojo> entry = iterator.next();
                String key = entry.getKey();
                chartStatisticsPojo = entry.getValue();
                if (key != null && (key.startsWith("num") || key.startsWith("count") || key.contains("computedField"))) {
                    FieldAttrPojo fieldAttrPojo = summaryAttrMap.get(key);
                    if (fieldAttrPojo != null){
                        Integer accuracy = fieldAttrPojo.getAccuracy();
                        accuracy = accuracy == null ? 0 : accuracy;
                        Integer groupingUsed = fieldAttrPojo.getGroupingUsed();
                        Integer percentUsed = fieldAttrPojo.getPercentUsed();
                        String resultDecimal = attrDecimalPrecisionHelper.getNumberFormat(chartStatisticsPojo.getValue(), accuracy, groupingUsed, percentUsed);
                        chartStatisticsPojo.setValue(resultDecimal);
                        map.put(key, chartStatisticsPojo);
                        pageList.set(i, map);
                    }
                }
                //如果只有一组数据,但是聚合有多个 会导致聚合 也会被解析
                if (chartStatisticsPojo.getSub() == null) {
                    continue;
                }
                valueList.add(chartStatisticsPojo.getValue());
                if (CollectionsUtil.isNotEmpty(chartStatisticsPojo.getSub())) {
                    List<LinkedHashMap<String, ChartStatisticsPojo>> lastFloorList = chartStatisticsPojo.getSub();
                    breFlag:
                    for (Map<String, ChartStatisticsPojo> lastFloor : lastFloorList) {
                        Iterator<Map.Entry<String, ChartStatisticsPojo>> lastFloorIterator = lastFloor.entrySet().iterator();
                        Map<String, ChartStatisticsPojo> summaryMapSub = new HashMap<>(BasicConstant.ONE);
                        int j = 0;
                        while (lastFloorIterator.hasNext()) {
                            j++;
                            Map.Entry<String, ChartStatisticsPojo> lastFloorEntry = lastFloorIterator.next();
                            ChartStatisticsPojo lastFloorStatisPojo = lastFloorEntry.getValue();
                            if (lastFloorStatisPojo.getSub() == null || lastFloorStatisPojo.getSub().size() == 0) {
                                if (j == 1) {
                                    Map<String, ChartStatisticsPojo> mapSub = new HashMap<>(BasicConstant.ONE);
                                    mapSub.put(lastFloorEntry.getKey(), lastFloorStatisPojo);
                                    mapList.add(mapSub);
                                } else {
                                    // 因为统计字段在最后一个层级sub，所以统计字段放进summaryMapList处理
                                    summaryMapSub.put(lastFloorEntry.getKey(), lastFloorStatisPojo);
                                }
                            } else if (CollectionsUtil.isNotEmpty(lastFloorStatisPojo.getSub())) {
                                mapList.addAll(chartStatisticsPojo.getSub());
                                break breFlag;
                            }
                        }
                        summaryMapList.add(summaryMapSub);
                    }
                }
                Iterator<Map.Entry<JSONObject, FieldAttrPojo>> iteratorJson = parseAttrMap.entrySet().iterator();
                if (i == pageList.size() - 1) {
                    while (iteratorJson.hasNext()) {
                        Map.Entry<JSONObject, FieldAttrPojo> parseAttrPojoEntry = iteratorJson.next();
                        JSONObject parseAttrJson = parseAttrPojoEntry.getKey();
                        if (key.equals(parseAttrJson.getString("key"))) {
                            FieldAttrPojo fieldAttrPojo = parseAttrPojoEntry.getValue();
                            fieldType = fieldAttrPojo.getFieldType();
                            try {
                                parseMap = chartResultHelp.valueListAnalysis(fieldAttrPojo, chartEntity.getCorpid(), valueList, chartEntity, true, null, true, baseDTO,null);
                            } catch (XbbException e) {
                                LOG.error("解析统计表出错", e);
                            }
                            break;
                        }
                    }
                }
            }
            if (i == pageList.size() - 1) {
                for (Map<String, ChartStatisticsPojo> parseValueMap : pageList) {
                    Iterator<Map.Entry<String, ChartStatisticsPojo>> iteratorValue = parseValueMap.entrySet().iterator();
                    while (iteratorValue.hasNext()) {
                        Map.Entry<String, ChartStatisticsPojo> entry = iteratorValue.next();
                        chartStatisticsPojo = entry.getValue();
                        String orginValue = chartStatisticsPojo.getValue();
                        if (chartStatisticsPojo.getSub() == null) {
                            continue;
                        }
                        if (parseMap != null) {
                            if (Objects.equals(fieldType, FieldTypeEnum.LINK_BUSINESS_SINGLE.getType()) || Objects.equals(fieldType, FieldTypeEnum.LINK_BUSINESS_MULTI.getType())) {
                                parseMap = chartResultHelp.parseLinkBusinessMap(parseMap);
                            }
                            String value = parseMap.get(orginValue);
                            //若解释的值是null 而原来的值是有值的,就显示以前值
                            if (StringUtil.isEmpty(value) && StringUtil.isNotEmpty(orginValue)) {
                                chartStatisticsPojo.setValue(orginValue);
                            } else {
                                chartStatisticsPojo.setValue(value);
                            }
                        }
                    }
                }
            }
            if (CollectionsUtil.isNotEmpty(mapList) && i == pageList.size() - 1) {
                parseAttrMap(mapList, parseAttrMap, summaryAttrMap, chartEntity, baseDTO);
            }
        }
        // 汇总字段 数字数据格式化
        summaryAttrFormat(summaryAttrMap, summaryMapList);
    }

    /**
     * 汇总字段 数字数据格式化
     *
     * @param summaryAttrMap 汇总字段实体映射
     * @param summaryMapList 汇总数据列表
     */
    private void summaryAttrFormat(Map<String, FieldAttrPojo> summaryAttrMap, List<Map<String, ChartStatisticsPojo>> summaryMapList) {
        if (CollectionsUtil.isEmpty(summaryMapList)) {
            return;
        }
        // 统计字段的解析，单独拎出来处理，因为统计字段结构与分组字段不同，不嵌套而是平级的
        for (Map<String, ChartStatisticsPojo> chartStatisticsPojoMap : summaryMapList) {
            Iterator<Map.Entry<String, ChartStatisticsPojo>> iterator = chartStatisticsPojoMap.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, ChartStatisticsPojo> entry = iterator.next();
                String key = entry.getKey();
                FieldAttrPojo fieldAttrPojo = summaryAttrMap.get(key);
                if (fieldAttrPojo == null || BusinessConstant.COUNT.equals(fieldAttrPojo.getAttr())) {
                    continue;
                }
                Integer accuracy = fieldAttrPojo.getAccuracy();
                accuracy = accuracy == null ? 0 : accuracy;
                Integer percentUsed = fieldAttrPojo.getPercentUsed();
                Integer groupingUsed = fieldAttrPojo.getGroupingUsed() == null ? fieldAttrPojo.getAmountFlag() : fieldAttrPojo.getGroupingUsed();
                String result = attrDecimalPrecisionHelper.getNumberFormat(entry.getValue().getValue(), accuracy, groupingUsed, percentUsed);
                entry.getValue().setValue(result);
            }
        }
    }

    /**
     * 递归计算汇总
     *
     * @param total                   小计的map
     * @param chartStatisticsPojoList ES的数据列表
     * @param result                  小组的汇总
     * @return Integer
     * @author yuqian
     * @date 2019/4/11 10:58
     * @since v1.0
     */
    private Integer recurrenceParseMap(Map<String, Object> total, List<LinkedHashMap<String, ChartStatisticsPojo>> chartStatisticsPojoList, Integer result, Map<String, FieldAttrPojo> summaryAttrMap) {
        if (CollectionsUtil.isNotEmpty(chartStatisticsPojoList)) {
            Map<String, Integer> totalCount = new HashMap<>();
            for (int i = 0; i < chartStatisticsPojoList.size(); i++) {
                Map<String, ChartStatisticsPojo> map = chartStatisticsPojoList.get(i);
                Iterator<Map.Entry<String, ChartStatisticsPojo>> it = map.entrySet().iterator();
                Map.Entry<String, ChartStatisticsPojo> mapEntry = it.next();
                ChartStatisticsPojo chartStatisticsPojo = mapEntry.getValue();
                if (CollectionsUtil.isEmpty(chartStatisticsPojo.getSub())) {
                    result = result + 1;
                    while (it.hasNext()) {
                        Map.Entry<String, ChartStatisticsPojo> entry = it.next();
                        String key = entry.getKey();
                        ChartStatisticsPojo totalPojo = entry.getValue();
                        //获取字段对应的属性实体
                        FieldAttrPojo fieldAttrPojo = summaryAttrMap.get(key);
                        //汇总方式
                        String aggType = AggTypeEnum.SUM.getAlias();
                        if (fieldAttrPojo != null) {
                            aggType = fieldAttrPojo.getAggType() == null ? AggTypeEnum.SUM.getAlias() : fieldAttrPojo.getAggType();
                        }
                        //未来考虑若汇总字段也需要表单那边控制 可以在这里加上判断进行精度控制
                        if (total.containsKey(key)) {
                            aggResult(key, total, totalPojo, aggType, totalCount);
                        } else {
                            total.put(key, Double.valueOf(totalPojo.getValue()));
                            totalCount.put(key, 1);
                            if (Objects.equals(aggType, AggTypeEnum.COUNT.getAlias())) {
                                // 汇总方式为计数
                                total.put(key, 1);
                            }
                        }
                    }
                }
                result = recurrenceParseMap(total, chartStatisticsPojo.getSub(), result, summaryAttrMap);
            }
        }
        return result;
    }

    /**
     * 对汇总字段进行汇总
     *
     * @param key       键
     * @param total     汇总
     * @param totalPojo pojo
     * @param aggType   汇总方式
     */
    private void aggResult(String key, Map<String, Object> total, ChartStatisticsPojo totalPojo, String aggType, Map<String, Integer> totalCount) {
        BigDecimal sumDecimal = new BigDecimal(total.get(key).toString());
        BigDecimal addDecimal = new BigDecimal(totalPojo.getValue());
        Integer count = totalCount.get(key) == null ? 1 : totalCount.get(key);
        AggTypeEnum aggTypeEnum = AggTypeEnum.getByAlias(aggType);
        switch (aggTypeEnum) {
            case MAX:
                sumDecimal = new BigDecimal(Math.max(sumDecimal.doubleValue(), addDecimal.doubleValue()));
                break;
            case MIN:
                sumDecimal = new BigDecimal(Math.min(sumDecimal.doubleValue(), addDecimal.doubleValue()));
                break;
            case AVG:
                count++;
                BigDecimal countDecimal = new BigDecimal(count);
                BigDecimal count1Decimal = new BigDecimal(count - 1);
                BigDecimal upDecimal = sumDecimal.multiply(count1Decimal).add(addDecimal);
                sumDecimal = upDecimal.divide(countDecimal, 6);
                totalCount.put(key, count);
                /*
                    n个数的平均值累积计算方法，a:累计总和；b:增量；n:当前总数；
                    累计平均值= a/（n -1）; 当前平均值 = (a+b)/n;
                    sumDecimal变量当前做为累计平均值，即 sumDecimal = a/(n-1);
                    count变量为当前总数，即 count = n;
                    addDecimal变量为增量，即 addDecimal = b;
                    所以计算当前平均值方程为：（a+b）/n =  ( a/(n-1) * (n-1) + b ) / n
                                                  = ( sumDecimal*(count-1) + addDecimal ) / count ;
                 */
                break;
            case COUNT:
                count++;
                total.put(key, count);
                totalCount.put(key, count);
                // return掉不走后面
                return;
            case SUM:
                sumDecimal = sumDecimal.add(addDecimal);
                break;
            default:
                sumDecimal = sumDecimal.add(addDecimal);
                break;
        }
        total.put(key, sumDecimal.doubleValue());
    }

    /**
     * 处理数值格式
     * @param chartResultPojo
     * @param jsonObject 回显数据
     * @param setEntity
     * @param keyTarget 目标值key
     * @param keyFinish 完成值key
     * @param target 目标值
     * @param finish 完成值
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2022/4/7 16:18
     * @version 1.0
     */
    private void handleNumFormat4Performance(ChartResultPojo chartResultPojo, JSONObject jsonObject, ChartEntity setEntity, String keyTarget, String keyFinish, Double target, Double finish) {
        Integer statisticsType = setEntity.getStatisticsType();
        Integer numFormat = NumFormatEnum.DEFAULT.getCode();
        // 系统金额图表和自定义图表处理数值格式
        if (Objects.equals(statisticsType, StatisticsTypeEnum.SYSTEM_STATISTIC.getCode())) {
            SystemCodeEnum systemCodeEnum = SystemCodeEnum.getByCode(setEntity.getSystemCode());
            // 目前系统目标只对金额字段做处理
            if (Objects.equals(systemCodeEnum.getHasAmount(), 1)) {
                // 系统目标存在最外层大表里
                numFormat = chartResultPojo.getNumFormat();
            }
        } else {
            // 自定义存在对应表里
            numFormat = setEntity.getNumFormat();
        }
        NumFormatEnum numFormatEnum = NumFormatEnum.getByCode(numFormat);
        // 非默认值处理数值格式
        if (!NumFormatEnum.DEFAULT.getCode().equals(numFormat)) {
            // 目标值-1前端回显未设置
            if (!Objects.equals(target, -1.0)) {
                jsonObject.put(keyTarget, ChartResultUtil.formatVal2Thousands(BigDecimal.valueOf(target), numFormatEnum));
            }
            jsonObject.put(keyFinish, ChartResultUtil.formatVal2Thousands(BigDecimal.valueOf(finish), numFormatEnum));
        }
    }


    /**
     * 数值格式单位处理
     * @param chartResultPojo
     * @param setEntity
     * @param systemCodeEnum
     * @param statisticsType
     * @param unit
     * @return java.lang.String
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2022/4/7 16:52
     * @version 1.0
     */
    private String handleUnit4NumFormat(ChartResultPojo chartResultPojo, ChartEntity setEntity, SystemCodeEnum systemCodeEnum, Integer statisticsType, String unit) {
        Integer numFormat;
        // 系统金额图表和自定义图表处理数值格式
        if (Objects.equals(statisticsType, StatisticsTypeEnum.SYSTEM_STATISTIC.getCode())) {
            // 目前系统目标只对金额字段做处理
            if (Objects.equals(systemCodeEnum.getHasAmount(), 1)) {
                // 系统目标存在最外层大表里
                numFormat = chartResultPojo.getNumFormat();
            } else {
                // 非金额类型返回原单位
                return unit;
            }
        } else {
            // 自定义存在对应表里
            if (Objects.equals(setEntity.getUnit(), UnitEnum.MONEY.getAlias())){
                numFormat = setEntity.getNumFormat() == null ? NumFormatEnum.DEFAULT.getCode() : setEntity.getNumFormat();
            }else {
                return unit;
            }
        }
        NumFormatEnum numFormatEnum = NumFormatEnum.getByCode(numFormat);
        return numFormatEnum.getUnit();
    }


}
